Haskell:通过电路示例了解箭头和单子

时间:2014-02-24 01:48:43

标签: haskell monads arrows

我试图通过编写一些我需要的东西来理解monad和箭头,当我读Haskell教程时,我觉得它们可能涉及人们正在谈论的内容,我想出了一个我能做的例子我的头脑很好:

newtype Stateful a b = Stateful { runStateful :: a -> (b, Stateful a b) }

stateful :: (a -> (b, Stateful a b)) -> Stateful a b
stateful = Stateful

-- executes a stateful computation, returning its result
evalStateful :: Stateful a b -> a -> b
evalStateful f x = fst $ runStateful f x

-- execStateful :: ??
execStateful = undefined

-- converts a stateful function to Stateful
close :: (s -> a -> (b, s)) -> s -> Stateful a b
close f s = stateful $ \x -> let (y, s') = f s x
                             in (y, close f s')

-- function composition
(<.>) :: Stateful a b -> Stateful b c -> Stateful a c
f <.> g = stateful $ \x -> let (y, f') = runStateful f x
                               (z, g') = runStateful g y
                           in (z, f' <.> g')

-- lifts a stateful computation to perform on lists
maps :: Stateful a b -> [a] -> [b]
maps f [] = []
maps f (x:xs) = let (x',f') = runStateful f x
                in x' : maps f' xs

所以我的想法是你有一个函数,它接受并返回像(a -> s -> (b, s))这样的状态,但是我们修改它以便不返回输出/状态元组而是返回一个输出/ X元组,其中X是与我们的初始功能相同的类型。所以有点像(a -> (b, a -> (b, ...)))。我最初试图创建类似于State monad的东西,但是不是返回状态返回与自身相同的函数,状态部分应用(因此状态和它应用的函数保持耦合在一起)。

所以我想也许这就像State monad所做的那样,但我想要的一个用例就是能够将多个有状态函数链接在一起,每个函数都有自己独立于其他函数的状态。我没有想出一种方法来以优雅的方式将类型(s -> a -> (b, s))(s' -> b -> (c, s'))的多个独立函数链接在一起,这不会导致返回的状态是一些丑陋的元组序列,如{{1你做的链越多,这让我觉得这可能比State monad更复杂。

我还读到了箭头,它用电路隐喻描述,并用于流处理,这符合我的设想。我看到有一个ArrowLoop,但是当我花了一段时间试图解决它时,似乎它更多地与聪明地使用懒惰而不是处理更新状态。然后我还读到IO monad使用某种类型系统技巧是不可避免的,这种感觉就像我用Stateful完成的那样;对于一个类型的Stateful不编码其内部状态的类型,因此很难(不可能?)推断(s''', (s'', (s', s)))的类型。另一方面,我无法想出任何有意义的绑定运算符。

所以我不确定我在做什么。我认为它至少是一个仿函数,因为fmap只是在电路结束时组成一个任意函数,确保内部状态管理保持不变。我几乎确信自己的绑定可以用同样的方式定义,但每当我试图将这个想法具体化时,它就会崩溃。任何人都可以对我正在使用的内容有所了解吗?这是一些普通的monad还是箭头?一个特定的 monad或箭头?

此外,使用此方法是否存在明显的问题或改进?我希望内部状态能够使用ST monad,因为我设想内部状态由昂贵的就地操作组成。但我并不了解各种抽象概念,知道我的设计是否可扩展。

编辑:我需要做的一件事是确保原始的有状态函数不能被引用,因为它将引用旧状态而不是新更新的状态,我不知道如何去做这样做。基本上runStateful只能在Stateful数据类型上使用一次,然后你需要确保下次运行它时使用返回的execStateful而不是原始的Stateful a b。内部管道可以使意外地防止变得微不足道,但我不确定如何使它变得不可能。

0 个答案:

没有答案