我想知道如何免费编写f x = zip x (tail x)
。所以我使用了pointfree程序,结果是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
的第一个参数,tail是ap
的第二个参数。
Monad m => m (a -> b) -> m a -> m b
\--------/ \---/
zip tail
但这是不可能的,因为zip
和tail
的类型与函数ap
所需的类型完全不同。即使考虑到该列表是一种单一的行列。
答案 0 :(得分:11)
因此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)
。我们已经看到我们所在的monad是(->) [x]
,而不是[]
。如果我们将{8}的类型签名替换为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。
答案 1 :(得分:6)
理解这一点有两个方面:
首先,这有助于我理解类型魔术:
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)
其次,信息流,即实际功能。这更容易,从<*>
的{{1}}的定义可以清楚地看出,Applicative instance of y →
使用不同的标识符名称并使用中缀样式重写:
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 )