Haskell '.' operator and '$' operator


已知:
data Tree a = Leaf a | Branch (Tree a) (Tree a)

ltree :: Tree a -> a -- fetch the left most leaf's data a
mapTree :: (a -> b) -> Tree a -> Tree b

tree :: Tree Integer

ltree $ mapTree (+2) tree -- 能返回正确的值
ltree . mapTree (+2) tree -- 出错

第一个 $ 运算符使得后面的所有内容作为之前的函数的参数, mapTree 能返回 Tree 类型数据,可行
第二个 . 运算符不是在第二个函数的返回值类型 与 第一个函数的参数类型 相同时就应该可以完成任务么? 為什麼出错了呢? '.' 的应用最重要的是要注意什么?

haskell

曾宇春的好朋友 12 years, 5 months ago

"."符号是函数组合符号。
Haskell中,函数调用后的空格从语义上来讲,就是一个函数调用的功能。

   
  f x=x
  

f 3 -- return 3,f和3之间的空格可以理解成一个类似infix运算符的东西。(" " f 3),当然,实际上不能这样调用

--也可以用 f $ 3
f $ 3 -- return 3,$是一个真正的infix运算符(函数),可以写成(($) f 3),注意,要加括号!!!

--而$和空格的区别在于优先级
--在ghci里,输入:info $
--得到

($) :: (a -> b) -> a -> b -- Defined in `GHC.Base'
infixr 0 $ --可以看到,"$"作为右结合infix运算符,其优先级是最低的0
--所以,在使用"$"的场合,都是为了让右边的表达式先求值,作为"$"的第二个参数
--因此,下面的代码
ltree $ mapTree (+2) tree
--等同于
ltree (mapTree (+2) tree)

--再看看".",它是一个infixl运算符,优先级为9(Haskell中infix level只有0-9,9已经是最高的),并且是左结合
--在ghci中输入":info ."的结果
(.) :: (b -> c) -> (a -> b) -> a -> c -- Defined in `GHC.Base'
infixr 9 .

--所以下面的代码:

ltree . mapTree (+2) tree
--等同于
(ltree.mapTree) (+2) tree
--即
((.) ltree mapTree) (+2) tree
--看到了吧,看"."的类型声明
--ltree为b->c是对的,但mapTree不符合,所以类型不匹配报错

--顺便,给个"."的正确用法,这样应该就对了
(ltree . (mapTree (+2))) tree

参考: Haskell infix

无谓的信仰 answered 12 years, 5 months ago

Your Answer