我有:
class Arrow circ ⇒ Circuit circ where
wire :: circ Bool Bool
notGate :: circ Bool Bool
orGate :: circ (Bool , Bool ) Bool
wire = id
notGate = arr not
orGate = arr $ uncurry (||)
我想实施:
-- A and B
andGate :: Circuit circ ⇒ circ (Bool , Bool ) Bool
-- not (A and B)
nandGate :: Circuit circ ⇒ circ (Bool , Bool ) Bool
-- A xor B
xorGate :: Circuit circ ⇒ circ (Bool , Bool ) Bool
我不想使用像(arr和)这样简单的东西,但结合已有的功能。我没有理解如何用函数来组合箭头。
谢谢。
答案 0 :(得分:3)
我建议您查看Control.Arrow
,特别是(***)
, (&&&)
, and (>>>)
。 This tutorial也非常好。
(***)
允许你拿两个箭头并将它们并排放入一个既有输入又有输出的箭头(作为元组):
(***) :: Arrow a => a b c -> a b' c' -> a (b, b') (c, c')
(&&&)
让你再次组合两个箭头并获得他们输出的元组,但这次两个箭头将消耗相同的输入:
(&&&) :: Arrow a => a b c -> a b c' -> a b (c, c')
(>>>)
可让您排序(撰写)两个箭头。这与功能组成非常相似。实际上,(>>>)
只是来自(.)
的广义Control.Category
,其参数被翻转。
(>>>) :: Arrow a => a b c -> a c d -> a b d
(实际上,约束只需要Category
,但这不是重点。)
然后,我们可以使用一些常见的逻辑等价来获得andGate
,nandGate
和xorGate
:
-- Use (x NAND y) === ((NOT x) OR (NOT y))
nandGate :: Circuit circ => circ (Bool, Bool) Bool
nandGate = (notGate *** notGate) >>> orGate
-- Use (x NAND y) === (NOT (x NAND y))
andGate :: Circuit circ => circ (Bool, Bool) Bool
andGate = nandGate >>> notGate
-- Use (x XOR y) === ((x OR y) AND (x NAND y))
xorGate :: Circuit circ => circ (Bool, Bool) Bool
xorGate = (orGate &&& nandGate) >>> andGate
-XArrows
有一个非常简洁的语法扩展,允许您使用特殊的Arrow
编写do
- 如符号。这比隐秘的Control.Arrow
运算符更具可读性,特别是当你有一堆箭头进行交互时。
{-# LANGUAGE Arrows #-}
nandGate :: Circuit circ => circ (Bool , Bool ) Bool
nandGate = proc (x,y) -> do
x' <- notGate -< x
y' <- notGate -< y
orGate -< (x',y')
andGate :: Circuit circ => circ (Bool, Bool) Bool
andGate = proc (x,y) -> do
z <- nandGate -< (x,y)
notGate -< z
xorGate :: Circuit circ => circ (Bool, Bool) Bool
xorGate = proc (x,y) -> do
z <- orGate -< (x,y)
w <- nandGate -< (x,y)
andGate -< (z,w)