代码之家  ›  专栏  ›  技术社区  ›  rampion

哈斯克尔:我是不是误解了箭的用法?

  •  17
  • rampion  · 技术社区  · 15 年前

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

    {-# 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是否适用于此,或者如何适用于此,因此跳过了它)之后,我定义了一些helper函数

    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
    

    但这有点尴尬,我希望有更自然的东西。

    1 回复  |  直到 15 年前
        1
  •  33
  •   C. A. McCann Ravikant Cherukuri    15 年前

    有人能解释一下我是如何误解箭的工作原理,以及它们是如何被使用的吗?有没有我所缺少的基本哲学?

    我觉得你在治疗这个 Arrow 就像你会 Monad join 函数;如何将嵌套结构折叠为单个层。它们有用是因为什么 参加 Functor 基于内容的结构,等等。但这不是关于 单子 s、 所以我们就到此为止。

    生命的本质 另一方面,是一个 函数的广义形式 Category 箭头 类型类定义如何将正则函数提升到 箭头 箭头 接受多个参数(以元组形式)的-- Arrows 不一定是咖喱做的!)。

    合并时 箭头 基本上是这样的,就像你第一次 countExample 功能,你真正要做的就是 功能组成 . 回顾一下你对 (.)

    所以,你的主要问题是 计数示例 提到 count' 诸如此类。这些都是在幕后完成的,就像使用时不需要显式传递state参数一样 do 中的符号 State 蒙纳德。

    现在,因为 proc 符号只是让你构造一个大的复合符号 箭头 使用 你的有状态函数你需要在 箭头 语法,就像你需要的 runState 或者类似的,以便在 蒙纳德。你的第二个 计数示例 是这样的,但是太专业了。在一般情况下,有状态函数映射 流动 输入到 流动 输出,使之成为 finite state transducer runStatefulFunction 可能需要一个输入值的延迟列表,并使用右折叠将它们转换为一个输出值的延迟列表 unSF 依次向传感器供电。

    如果你想看一个例子 arrows includes an Arrow transformer Automaton 它定义了一些和你的 StatefulFunction ,除非带有任意的 箭头 代替你用的普通函数。


    哦,再简单回顾一下 s和 单子 学生:

    朴素的 箭头 只是“一阶”函数之类的东西。正如我之前所说的,它们不可能总是被讨好,同样地,它们也不可能总是被“应用”在相同的意义上 ($) 函数应用函数。如果你真的想要更高阶的 箭头 ,类型类 ArrowApply 定义应用程序 太好了 对一个 除此之外,它还允许相同的“折叠嵌套结构”功能 单子 提供,使定义 单子 箭头应用 实例。

    单子 允许组合函数来创建新的一元结构 单子 m 你可以说一个“Kleisli箭头”,它是类型的函数 a -> m b . Kleisli箭头 箭头 很明显的例子。

    箭头应用