下面是Haskell代码:
zipWith compare `ap` tail
字符串
哪里
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
compare :: a -> a -> Ordering
ap :: Monad m => m (a -> b) -> m a -> m b
型
因此,根据我的理解,ap
在这种情况下需要一个 Package 在列表monad中的函数,也就是说它需要m (a -> b)
,这应该是由zipWith compare
完成的,但我不知道如何实现,因为zipWith compare
将采用[a] -> [a] -> [Ordering]
类型,这是不完全正确的。
代码工作,并不是我自己的工作,我只是想了解它是如何被允许的。
2条答案
按热度按时间i34xakig1#
这里的诀窍是
a ->
是一个Monad!事实上,我们可以在一个普通的ghci会话中列出Monad的示例:
字符串
因此,
zipWith compare :: m ([a] -> Ordering)
和tail :: m [a]
,其中m
是((->) [a])
,或([a] ->)
。这里的技巧是,函数arrow
->
实际上是一个构建新类型的类型构造函数。一旦解决了这个问题,你可以看看它的Monad示例的实际实现(那里没有什么出乎意料的)。事实上,对于
ap
(我没有仔细检查过,但我很有信心),它看起来像这样:型
这也是SKI中的S-combinator。
z4bn682m2#
但我不知道怎么做,因为
zipWith compare
将采用[a] -> [a] -> [Ordering]
类型,这是不完全正确的。不,该类型有正确的形式。一开始并不明显,但该类型确实匹配
m (t -> u)
,因此可以在这里使用ap
。为了理解为什么,我们需要回忆一下
A -> B
是(->) A B
的语法糖。这是类型构造函数(->)
应用于A
,然后再次应用于B
。我们也可以将其写为((->) A) B
。那么,让我们匹配类型:
字符串
因此,我们可以取
m = (->) [a]
、t = [a]
和u = [Ordering]
来满足将其传递给ap
的要求。型
最后,请注意
m = (->) [a]
确实是一个monad,它本质上与Reader [a]
monad相同,只是没有newtype
Package 器。