我希望Automaton拥有实例ArrowApply,但Control.Arrow.Transformer.Automaton却没有。 我认为以下代码表现良好:
data Automaton b c = Auto {runAuto :: b -> (c, Automaton b c) }
app :: Automaton (Automaton b c, b) c
app = Auto $ \(f,x) -> let
(u, m) = runAuto f x
nextApp m = Auto $ \(_,x) -> let
(u', n) = runAuto m x
in (u', nextApp n)
in (u, nextApp m)
可能存在未使用的参数并不好。 但是我不能对坏的例子有任何具体的想法,请告诉我任何一个。
答案 0 :(得分:4)
它不会满足ArrowApply laws,
实际上它违反了第一部法律:
first (arr (\x -> arr (\y -> (x,y)))) >>> app = id
:: ArrowApply a => a (t, d) (t, d)
让我们首先定义辅助函数:
iterateAuto :: [b] -> Auto b c -> [c]
iterateAuto [] _ = []
iterateAuto (x:xs) a = let (y, a') = runAuto a x
in y : iterateAuto xs a'
在右侧我们得到:
*Main> iterateAuto [(0,0), (1,0)] (id :: Auto (Int, Int) (Int, Int))
[(0,0),(1,0)]
但是在左侧(这里我必须将您的实施命名为app'
)
iterateAuto [(0,0), (1,0)] (first (arr (\x -> arr (\y -> (x,y)))) >>> app' :: Auto (Int, Int) (Int, Int))
[(0,0),(0,0)]
我非常确定ArrowApply
Automaton
是否可行,它会在arrows
个包中。很难解释为什么不能成为一个人。我试着解释我的直觉。 ArrowApply
相当于Monad
,app
是一种join
。 Automaton
是一种有状态计算,但每个Automaton
都有自己的状态,而不是State
monad中的全局状态。在纯设置中,结果对中的每次迭代都会向我们提供自动机的下一个状态。然而,如果我们有app
,内部自动机的状态就会丢失。
app
的另一个天真实现:
app'' :: Auto (Auto b c, b) c
app'' = Automaton $ \(f,x) -> let
(u, m) = runAuto f x
nextApp = app''
in (u, nextApp)
将在第二部法律上失败
first (arr (g >>>)) >>> app = second g >>> app
让我们将有状态incr
作为g
incr :: Auto Int Int
incr = incr' 0
where incr' n = Automaton $ \x -> (x + n, incr' $ n + 1)
和辅助方法
helper :: Arrow a => (Int, Int) -> (a Int Int, Int)
helper (x, y) = (arr (+x), y)
然后我们看到方程式也不适用于非常简单的输入:
*Main> iterateAuto (map helper [(0,0),(0,0)]) $ first (arr (incr >>>)) >>> app''
[0,0]
*Main> iterateAuto (map helper [(0,0),(0,0)]) $ second incr >>> app''
[0,1]
一个邪恶的想法是通过利用IORef或STRef
制作自动机版本data STAutomaton s a b c = STAutomaton (STRef s (Automaton a b c))
但这可能是使用Kleisli (ST s)
或Kleisli IO
的尴尬方式。