箭头函数相较于普通函数的优势

5
箭头在Haskell中相比于普通函数有哪些优势?它们能做到函数所不能的事情吗?函数可以使用fmap映射结构。
2个回答

6

从更广阔的角度来看,箭头能够帮助你走出Hask范畴,进入其他有待探索的范畴。Kleisli范畴可能是Haskeller最熟悉的,其次是Cokleisli。这些都是Hask的自然“扩展”:在结果或参数周围添加一个自函子,然后如果满足条件,则再次得到一个范畴。

  • Kleisli: the functor is a monad, so id ≅ return :: a -> m a

    (.) ≅ (<=<) :: (b->m c) -> (a->m b) -> a->m c
    
  • CoKleisli: the functor is a comonad, so id ≅ coreturn :: m a -> a and

    (.)     ::     (m b->c) -> (m a->b) -> m a->c
    

现在你还不需要使用 Arrow,只需要使用 Category。但是常规类别并不是非常有趣,通常你需要 幺半范畴(monoidal),甚至是 笛卡尔闭范畴(cartesian closed),这就是 Arrow 大致所针对的。

但是确实有很多其他类别。大多数与 Hask 没有太多关系,不能用标准的 Arrow 类来表示,主要是因为对象具有特殊属性,而不是每个 Haskell 类型都满足。事实上,如果你添加了约束对象类型的能力,可能性立即变得更广泛。但即使你仍然使用标准类别,甚至只是使用 ->,箭头自然的点无风格组合方式通常会变得非常好、简洁,并开启了新的思考转换的方式。


3

函数只是箭头的一种实例,就像问“为什么要使用单子而不是只用Maybe一样”。

当然,你可以用函数来完成任何箭头所能完成的事情,因为Arrow (->)实例只能涉及到函数中很小的部分,即Arrow类型类中的内容。然而,箭头有比普通函数更多的实例,所以我们可以使用同样的函数来操作更复杂的类型。

箭头很好用,因为它们可以具有比函数更多的结构。当只用fmap进行遍历时,我们没有办法累积效果,而箭头比单子更具表现力!考虑Kleisli箭头,

newtype Kleisli m a b = Kleisli {runKleisli :: a -> m b}

m 是一个单子时,它形成了一个箭头。因此,每个 Monad 都形成了一条箭头,我们可以通过无缝组合 a -> m b 来构建单子计算,并做出各种有用的事情。一些 XML 库使用箭头来抽象从元素到其子元素的功能,并使用它来遍历文档。其他解析器使用箭头(它们最初的目的)尽管现在这似乎已经不再受欢迎,而改为使用 Applicative
你可能已经注意到的是,箭头更加通用。当我们只讨论箭头时,我们避免了重复编写与解析器、XML 抓取程序和单子函数相关的所有代码!
这就像选择 Monad 而不是 Maybe 一样,我们失去了一些能力,因为我们不能再做出具体的陈述,但我们得到了更通用的代码。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接