我想知道如何免费编写f x = zip x (tail x)。所以我使用了无点程序,结果是f = ap zip tail。ap是Control.Monad的一个函数
我不明白这个无意义的定义是如何运作的。我希望我能从类型的角度来理解它。
import Control.Monad (ap)
let f = ap zip tail
let g = ap zip
:info ap zip tail f g
ap :: Monad m => m (a -> b) -> m a -> m b
-- Defined in `Control.Monad'
zip :: [a] -> [b] -> [(a, b)] -- Defined in `GHC.List'
tail :: [a] -> [a] -- Defined in `GHC.List'
f :: [b] -> [(b, b)] -- Defined at <interactive>:3:5
g :: ([a] -> [b]) -> [a] -> [(a, b)]
-- Defined at <interactive>:4:5通过查看表达式ap zip tail,我会认为zip是ap的第一个参数,尾巴是ap的第二个参数。
Monad m => m (a -> b) -> m a -> m b
\--------/ \---/
zip tail但这是不可能的,因为zip和tail的类型与ap所需的函数完全不同。即使考虑到名单是一个单一的种类。
发布于 2013-10-04 13:34:06
因此,ap的类型签名是Monad m => m (a -> b) -> m a -> m b。您已经将它作为参数给出了zip和tail,所以让我们看看它们的类型签名。
从tail :: [a] -> [a] ~ (->) [a] [a]开始(这里~是类型的相等运算符),如果我们将这种类型与ap的第二个参数的类型进行比较,
(->) [x] [x] ~ m a
((->) [x]) [x] ~ m a我们得到了a ~ [x]和m ~ ((->) [x]) ~ ((->) a)。我们已经可以看到,我们所处的单一模式是(->) [x],而不是[]。如果我们将可能的内容替换为ap的类型签名,就会得到:
(((->) [x]) ([x] -> b)) -> (((->) [x]) [x]) -> (((->) [x]) b)因为这不是很好的可读性,所以它通常可以写成
([x] -> ([x] -> b)) -> ([x] -> [x]) -> ([x] -> b)
~ ([x] -> [x] -> b ) -> ([x] -> [x]) -> ([x] -> b)zip的类型是[x] -> [y] -> [(x, y)]。我们已经可以看到,这与ap的第一个参数是一致的
[x] ~ [x]
[y] ~ [x]
[(x, y)] ~ b在这里,我列出了垂直的类型,这样您就可以很容易地看到哪些类型排列起来。所以很明显,x ~ x,y ~ x和[(x, y)] ~ [(x, x)] ~ b,所以我们可以完成将b ~ [(x, x)]替换成ap的类型签名并获得
([x] -> [x] -> [(x, x)]) -> ([x] -> [x]) -> ([x] -> [(x, x)])
-- zip tail ( ap zip tail )
-- ap zip tail u = zip u (tail u)我希望这能帮你弄清楚。
编辑:作为评论中的danvari pointed out,monad (->) a有时被称为读取器monad。
发布于 2015-09-16 02:22:49
要理解这一点有两个方面:
首先,这帮助我理解了类型的魔术:
1) zip : [a] → ( [a] → [(a,a)] )
2) tail : [a] → [a]
3) zip <*> tail : [a] → [(a,a)]
4) <*> : Applicative f ⇒ f (p → q) → f p → f q在这种情况下,对于<*>来说,
5) f x = y → x注意,在5中,f是一个类型构造函数。将f应用于x会产生一种类型。此外,在这里,=被重载为类型的等价性。
y目前是位持有者,在本例中,它是[a],这意味着
6) f x = [a] -> x使用6,我们可以重写1,2和3如下:
7) zip : f ([a] → [(a,a)])
8) tail : f [a]
9) zip <*> tail : f ([a] → [(a,a)]) → f [a] → f [(a,a)]因此,看看4,我们用以下几个字来代替:
10) p = [a]
11) q = [(a,a)]
12) f x = [a] → x(在此再次重复6次为12次)
其次,信息流,即实际的功能。这比较容易,从y →的定义可以看出,这里用不同的标识符名重写了y →,并使用infix样式:
13) g <*> h $ xs = g xs (h xs)代以:
14) g = zip
15) h = tail给予:
zip <*> tail $ xs (Using 14 and 15)
==
zip xs (tail xs) (Using 13 )https://stackoverflow.com/questions/19181917
复制相似问题