与haskell中的常规函数相比,箭头有什么优势。他们能做什么功能不能。函数可以使用 fmap 映射结构。
2 回答
从更广泛的角度来看,箭头会让你脱离Hask并进入其他有待探索的类别。Kleisli 类别可能是 Haskeller 最熟悉的类别,其次是Cokleisli。这些是Hask的自然“扩展” :在结果或参数周围添加一个 endofunctor,然后如果
Kleisli
:函子是一个单子,所以id ≅ return :: a -> m a
(.) ≅ (<=<) :: (b->m c) -> (a->m b) -> a->m c
CoKleisli
: 函子是一个共单子,所以id ≅ coreturn :: m a -> a
和(.) :: (m b->c) -> (m a->b) -> m a->c
(为此,您还不需要Arrow
,只有Category
。但是一般类别不是很有趣,您通常需要幺半群甚至笛卡尔封闭类别,这就是Arrow
大致目标。)
但肯定还有很多其他类别。大多数与Hask没有太大关系,也不能用标准Arrow
类来表达,主要是因为对象具有并非每个 Haskell 类型都满足的特殊属性。实际上,如果您添加约束对象类型的能力,可能性会立即变得更广泛。但是,即使您使用标准类,甚至可能只是简单地在 中->
,带有箭头的自然无点组合样式通常会非常漂亮、简洁,并开辟了思考转换的新方法。
函数只是箭头的一个实例,就像在问“为什么使用 monad 而不是仅仅Maybe
”。
你可以用箭头做的任何事情当然可以用函数来完成,因为Arrow (->)
实例只能谈论一小部分函数,即Arrow
类型类中的内容。但是,arrows 的实例不仅仅是普通函数,因此我们可以使用 ssame 函数来操作更复杂的类型。
箭头很好,因为它们可以具有比函数更多的结构,当使用 just 遍历时fmap
,我们无法累积效果,比 monad 更具表现力!考虑 Kleisli 箭头,
newtype Kleisli m a b = Kleisli {runKleisli :: a -> m b}
当m
是一个单子时,这会形成一个箭头。所以每个都Monad
形成一个箭头,因此我们可以通过无缝组合 's 来建立单子计算,a -> m b
并做各种类似的有用的事情。一些 XML 库使用箭头来抽象从元素到其子元素的函数,并使用它来遍历文档。其他解析器使用箭头(它们最初的目的),尽管现在这似乎不再受Applicative
.
您希望注意到的一点是箭头更通用,当我们只谈论箭头时,我们避免复制我们需要编写的所有代码来使用我们的解析器、xml 抓取器和 monadic 函数!
这就像选择Monad
over一样Maybe
,我们失去了一些权力,因为我们不再能够做出特定的陈述,但我们得到了更通用的代码作为回报。