哈斯克尔:我误解了如何使用箭头?

时间:2010-09-10 15:52:18

标签: haskell arrows

我写了一些玩具代码来玩Arrows的概念。我想看看是否可以编写一个编码有状态函数概念的箭头 - 在不同的调用后给出不同的值。

{-# LANGUAGE Arrows#-}
module StatefulFunc where

import Control.Category
import Control.Arrow

newtype StatefulFunc a b = SF { unSF :: a -> (StatefulFunc a b, b) }

idSF :: StatefulFunc a a
idSF = SF $ \a -> (idSF, a)

dotSF :: StatefulFunc b c -> StatefulFunc a b -> StatefulFunc a c
dotSF f g = SF $ \a -> 
    let (g', b) = unSF g a
        (f', c) = unSF f b
    in (dotSF f' g', c)

instance Category StatefulFunc where
  id = idSF
  (.) = dotSF

arrSF :: (a -> b) -> StatefulFunc a b
arrSF f = ret
  where ret = SF fun
        fun a = (ret, f a)

bothSF :: StatefulFunc a b -> StatefulFunc a' b' -> StatefulFunc (a, a') (b, b')
bothSF f g = SF $ \(a,a') ->
    let (f', b) = unSF f a
        (g', b') = unSF g a'
    in (bothSF f' g', (b, b'))

splitSF :: StatefulFunc a b -> StatefulFunc a b' -> StatefulFunc a (b, b')
splitSF f g = SF $ \a ->
    let (f', b) = unSF f a
        (g', b') = unSF g a
    in (splitSF f' g', (b, b'))

instance Arrow StatefulFunc where
  arr  = arrSF
  first = flip bothSF idSF
  second = bothSF idSF
  (***) = bothSF
  (&&&) = splitSF

eitherSF :: StatefulFunc a b -> StatefulFunc a' b' -> StatefulFunc (Either a a') (Either b b')
eitherSF f g = SF $ \e -> case e of
      Left a -> let (f', b) = unSF f a in (eitherSF f' g, Left b)
      Right a' -> let (g', b') = unSF g a' in (eitherSF f g', Right b')

mergeSF :: StatefulFunc a b -> StatefulFunc a' b -> StatefulFunc (Either a a') b
mergeSF f g = SF $ \e -> case e of 
      Left a -> let (f', b) = unSF f a in (mergeSF f' g, b)
      Right a' -> let (g', b) = unSF g a' in (mergeSF f g', b)

instance ArrowChoice StatefulFunc where
  left = flip eitherSF idSF
  right = eitherSF idSF
  (+++) = eitherSF
  (|||) = mergeSF

所以在我完成各种类型类定义后(不确定ArrowZero是否或如何为此工作,所以我跳过它),我定义了一些辅助函数

evalSF :: (StatefulFunc a b) -> a -> b
evalSF f a = snd (unSF f a)

givenState :: s -> (s -> a -> (s, b)) -> StatefulFunc a b
givenState s f = SF $ \a -> let (s', b) = f s a in (givenState s' f, b)

并制定了一个使用示例

count :: StatefulFunc a Integer
count = givenState 1 $ \c _ -> (c+1, c)

countExample :: StatefulFunc a Integer
countExample = proc _ -> do
                  (count', one) <- count -< ()
                  (count'', two) <- count' -< ()
                  (count''', three) <- count'' -< ()
                  returnA -< three

但是,当我尝试编译countExample时,count'count''会出现“不在范围内”的错误,我想这意味着我需要回到教程并阅读什么时候可以使用。我认为我真正喜欢的东西更像是

countExample :: Integer
countExample =
  let (count', one) = unSF count ()
      (count'', two) = unSF count' ()
      (count''', three) = unSF count'' ()
  in three

但这有点尴尬,我希望有点自然。

任何人都可以解释我是如何误解Arrows是如何工作的,以及它们如何被使用?我错过了Arrows的基本哲学吗?

1 个答案:

答案 0 :(得分:33)

  

任何人都可以解释我是如何误解Arrows是如何工作的,以及它们如何被使用?我错过了Arrows的基本哲学吗?

我得到的印象是,您要像对待Arrow一样对待这个Monad。我不知道这是否算作“基本哲学”,但两者之间存在显着差异,尽管它们经常重叠。从某种意义上说,定义Monad的关键是join函数;如何将嵌套结构折叠为单个图层。由于join允许,它们很有用:您可以在递归函数中创建新的monadic图层,根据其内容更改Functor结构,依此类推。但这不是关于Monad s,所以我们将其留在那里。

另一方面,Arrow的本质是广义的函数版本Category类型类定义了函数组合和标识函数的通用版本,而Arrow类型类定义了如何将常规函数提升为Arrow以及如何使用{{1}带有多个参数的s(以元组的形式 - Arrow不一定是咖喱!)。

以基本方式组合Arrows时,就像在您的第一个Arrow函数中一样,您所做的一切就像精心设计的功能组合。回顾一下countExample的定义 - 你正在使用两个有状态函数并将它们连接成一个有状态函数,状态更改行为会自动处理。

因此,(.)的主要问题是它甚至提及 countExample等。这些都是在幕后完成的,就像在count' monad中使用do表示法时不需要显式传递状态参数一样。

现在,因为State表示法只允许您构建大型复合proc,实际使用您的有状态函数,您需要在{{1}之外工作语法,就像你需要Arrow之类的,以便在Arrow monad中实际运行计算。你的第二个runState沿着这些方向,但太专业了。在一般情况下,您的有状态函数将输入的映射到输出的,使其成为finite state transducer,因此可能State获取一个惰性的输入值列表,并使用countExample的右侧折叠将它们转换为输入值的惰性列表,以便依次将每个输入值提供给传感器。

如果您想查看示例,runStatefulFunctionincludes an Arrow transformer Automaton定义的内容几乎与您的unSF完全相同,除非有arrows代替StatefulFunction您使用的普通功能。


哦,并简要回顾一下ArrowArrow之间的关系:

普通Monad只是“一阶”函数式的东西。正如我之前所说,它们不能总是被咖喱,同样它们也不能总是被“应用”,就像Arrows函数应用函数一样。如果您确实需要更高阶($),则类型类Arrows会定义应用程序ArrowApply。这为Arrow增加了很多的功能,除此之外,还允许Arrow提供相同的“崩溃嵌套结构”功能,从而可以定义任何Monad实例的Monad实例。

在另一个方向,因为ArrowApply允许组合创建新monadic结构的函数,对于任何Monad Monad,你可以谈论一个“Kleisli箭头”,这是一个函数类型为ma -> m b的Kleisli箭头可以以非常明显的方式给出Monad实例。

除了Arrow和Kleisli箭头之外,类型类之间没有特别有趣的关系。