Haskell 函数应用程序绑定的括号
Haskell parentheses for function application binding
我正在学习 Haskell。我定义了以下函数(我知道我不需要 addToList
我也可以做 Point-free notation 我只是在玩语言概念的过程中):
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = addToList (f x) map f xs
where
addToList :: a -> [a] -> [a]
addToList x [] = [x]
addToList x xs = x:xs
这会产生编译错误:
with actual type `(a0 -> b0) -> [a0] -> [b0]'
Relevant bindings include
f :: a -> b (bound at PlayGround.hs:12:5)
map :: (a -> b) -> [a] -> [b] (bound at PlayGround.hs:11:1)
Probable cause: `map' is applied to too few arguments
In the second argument of `addToList', namely `map'
In the expression: addToList (f x) map f xs
如果我在地图周围加上括号,它会起作用:
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = addToList (f x) (map f xs)
where
addToList :: a -> [a] -> [a]
addToList x [] = [x]
addToList x xs = x:xs
我知道函数应用程序比运算符绑定得更紧密(如 Haskell - too few arguments 中所述),但是,我不明白编译器在没有括号的情况下如何以不同方式解析上述内容。
查看错误的简单方法是注意表达式:
addToList (f x) map f xs
将 4 个参数应用到 addToList
而:
addToList (f x) (map f xs)
将两个参数应用到 addToList
(这就是 addToList
"expects")。
更新
请注意,即使 map
有两个参数,这个表达式:
addToList a map c d
解析为:
(((addToList a) map) c) d
所以这是对 GHC 的想法的可能解释...
addToList (f x)
具有类型 [a] -> [a]
- 即它是一个接受列表的函数。
map
的类型为 (c -> d) -> [c] -> [d]
。它不是一个列表,但可以通过附加参数生成一个列表。
因此,当 GHC 看到 addTolist (f x) map
并且无法对其进行类型检查时,它会看到 if map
只有几个参数,如下所示:
addToList (f x) (map ...)
至少 addToList
的第二个参数是一个列表 - 所以这可能就是问题所在。
解析是一个独特的步骤,它在类型检查发生之前完成。表达式
addToList (f x) map f xs
对解析器的意义与 s1 (s2 s3) s4 s2 s5
对你的意义一样大。它不知道名称 的意思 是什么。它采用字符串的词法结构并将其转换为像
这样的解析树
*5
/ \
/ xs
*4
/ \
/ f
*3
/ \
/ map
*2
/ \
addToList *1
/ \
f x
一旦解析树完成,每个节点就会被标记上它的类型,并且可以进行类型检查。由于函数应用程序只是通过并列来表示,类型检查器知道节点的左子节点是一个函数,右子节点是参数,根节点是结果。
类型检查器可以大致如下进行,对树进行预序遍历。 (我会稍微改变类型签名以区分不相关的类型变量,直到它们统一为止。)
addToList :: a -> [a] -> [a]
,所以它需要一个 a
类型的参数和 returns 类型 [a] -> [a]
的函数。 a
的值尚不清楚。
f :: b -> c
,所以它需要一个 b
类型的参数和 returns 类型 c
的值。 b
和 c
的值尚不清楚。
x
的类型为 d
。 d
的值尚不清楚。
- 让
b ~ d
,f
可以应用到x
,所以*1 :: c
- 让
a ~ c
、addToList
应用于*1
,所以*2 :: [a] -> [a]
- 呃哦。
*2
需要类型为 [a]
的参数,但它被应用于 map :: (e -> f) -> [e] -> [f]
。类型检查器不知道如何统一列表类型和函数类型,这会产生您看到的错误。
我正在学习 Haskell。我定义了以下函数(我知道我不需要 addToList
我也可以做 Point-free notation 我只是在玩语言概念的过程中):
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = addToList (f x) map f xs
where
addToList :: a -> [a] -> [a]
addToList x [] = [x]
addToList x xs = x:xs
这会产生编译错误:
with actual type `(a0 -> b0) -> [a0] -> [b0]'
Relevant bindings include
f :: a -> b (bound at PlayGround.hs:12:5)
map :: (a -> b) -> [a] -> [b] (bound at PlayGround.hs:11:1)
Probable cause: `map' is applied to too few arguments
In the second argument of `addToList', namely `map'
In the expression: addToList (f x) map f xs
如果我在地图周围加上括号,它会起作用:
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = addToList (f x) (map f xs)
where
addToList :: a -> [a] -> [a]
addToList x [] = [x]
addToList x xs = x:xs
我知道函数应用程序比运算符绑定得更紧密(如 Haskell - too few arguments 中所述),但是,我不明白编译器在没有括号的情况下如何以不同方式解析上述内容。
查看错误的简单方法是注意表达式:
addToList (f x) map f xs
将 4 个参数应用到 addToList
而:
addToList (f x) (map f xs)
将两个参数应用到 addToList
(这就是 addToList
"expects")。
更新
请注意,即使 map
有两个参数,这个表达式:
addToList a map c d
解析为:
(((addToList a) map) c) d
所以这是对 GHC 的想法的可能解释...
addToList (f x)
具有类型[a] -> [a]
- 即它是一个接受列表的函数。map
的类型为(c -> d) -> [c] -> [d]
。它不是一个列表,但可以通过附加参数生成一个列表。因此,当 GHC 看到
addTolist (f x) map
并且无法对其进行类型检查时,它会看到 ifmap
只有几个参数,如下所示:addToList (f x) (map ...)
至少 addToList
的第二个参数是一个列表 - 所以这可能就是问题所在。
解析是一个独特的步骤,它在类型检查发生之前完成。表达式
addToList (f x) map f xs
对解析器的意义与 s1 (s2 s3) s4 s2 s5
对你的意义一样大。它不知道名称 的意思 是什么。它采用字符串的词法结构并将其转换为像
*5
/ \
/ xs
*4
/ \
/ f
*3
/ \
/ map
*2
/ \
addToList *1
/ \
f x
一旦解析树完成,每个节点就会被标记上它的类型,并且可以进行类型检查。由于函数应用程序只是通过并列来表示,类型检查器知道节点的左子节点是一个函数,右子节点是参数,根节点是结果。
类型检查器可以大致如下进行,对树进行预序遍历。 (我会稍微改变类型签名以区分不相关的类型变量,直到它们统一为止。)
addToList :: a -> [a] -> [a]
,所以它需要一个a
类型的参数和 returns 类型[a] -> [a]
的函数。a
的值尚不清楚。f :: b -> c
,所以它需要一个b
类型的参数和 returns 类型c
的值。b
和c
的值尚不清楚。x
的类型为d
。d
的值尚不清楚。- 让
b ~ d
,f
可以应用到x
,所以*1 :: c
- 让
a ~ c
、addToList
应用于*1
,所以*2 :: [a] -> [a]
- 呃哦。
*2
需要类型为[a]
的参数,但它被应用于map :: (e -> f) -> [e] -> [f]
。类型检查器不知道如何统一列表类型和函数类型,这会产生您看到的错误。