这是previous question; I got an answer I didn't really understand的后续行动,但已被接受。所以我会再问一遍。
我仍然不明白这有多大意义:
type Parse a b = [a] -> [(b,[a])]
build :: Parse a b -> ( b -> c ) -> Parse a c
build p f inp = [ (f x, rem) | (x, rem) <- p inp ]
现在,显然,p
绑定到Parse a b
类型的第一个参数。而且,显然f
绑定到第二个参数(b -> c)
。我的问题仍然是inp
绑定到什么?
如果Parse a b
是[a] -> [(b,[a])]
的类型同义词我从上一个问题中想到我可以替代它:
build :: [a] -> [(b,[a])] -> ( b -> c ) -> [a] -> [(c,[a])]
但是,我没有看到这个定义有任何意义:
build p f inp = [ (f x, rem) | (x, rem) <- p inp ]
有人帮助解释类型同义词。
答案 0 :(得分:8)
现在,显然,p绑定了Parse a b类型的第一个参数。而且,显然f与第二个参数(b - > c)结合。我的问题仍然是inp绑定到什么?
[a]
如果Parse a b是[a]的类型同义词 - &gt; [(b,[a])]我从上一个问题中想到我可以替代它:
build :: [a] -> [(b,[a])] -> ( b -> c ) -> [a] -> [(c,[a])]
几乎;你需要为替换加上括号:
build :: ([a] -> [(b,[a])]) -> ( b -> c ) -> ([a] -> [(c,[a])])
因为->
是右关联的,所以你可以删除末尾的括号,但不能删除开头的括号,所以你得到:
build :: ([a] -> [(b,[a])]) -> ( b -> c ) -> [a] -> [(c,[a])]
这应该明确为什么inp
具有[a]
类型。
答案 1 :(得分:5)
你可以替代 - 但不要忘记括号!那应该是:
build :: ( [a] -> [(b,[a])] ) -> ( b -> c ) -> ( [a] -> [(c,[a])] )
因为函数箭头是右关联的,你可以转储右边的括号组,但至关重要的是你不能丢弃左边的新符号:
build :: ( [a] -> [(b,[a])] ) -> ( b -> c ) -> [a] -> [(c,[a])]
所以现在当你有build p f inp
行时,你可以看到:
p :: ( [a] -> [(b,[a])] )
f :: ( b -> c )
inp :: [a]
那么我们就可以看到:
p inp :: [(b, [a])]
因此:
x :: b
rem :: [a]
和
f x :: c
(f x, rem) :: (c, [a])
因此整个列表理解的类型为[(c, [a])]
- 它与build
应返回的内容完全匹配。希望有所帮助!
答案 2 :(得分:4)
如果替换
type Parse a b = [a] -> [(b,[a])]
到
build :: Parse a b -> ( b -> c ) -> Parse a c
你得到了
build :: ([a] -> [(b,[a])]) -> (b -> c) -> [a] -> [(c,[a])]
请注意,x -> y -> z
是x -> (y -> z)
的简写,与(x -> y) -> z
非常不同。第一个函数接受两个参数x
,y
并返回z
[正好它需要一个参数x并返回一个函数,它接受y并返回z];第二个是函数 x -> y
并返回z
。
答案 3 :(得分:3)
这里要记住的重要一点是类型签名中的箭头->
是右关联的。类型a -> (b -> c)
与类型a -> b -> c
相同。
所以类型
Parse a b -> ( b -> c ) -> Parse a c
解析为
([a] -> [(b,[a])]) -> ( b -> c ) -> ([a] -> [(c,[a])])
通过关联性,您可以删除最后一个parens,但不能删除第一个parens。这给了你
([a] -> [(b,[a])]) -> ( b -> c ) -> [a] -> [(c,[a])]
允许您使用3个参数为build
编写公式。