2017-07-23 42 views
1

对于Haskell语法和函数式编程语言,我仍然是初学者,所以当我查看Data.Function.on的类型声明,即on :: (b -> b -> c) -> (a -> b) -> a -> a -> c时,我的解释是它需要四个参数: (b -> b -> c),(a -> b),a,a,并且返回c。但是,当我查看Data.Function.on的一般使用语法(*) `on` f = \x y -> f x * f y时,它只取两个函数参数,而不是四个,那么类型签名与使用语法的关系如何?了解Data.Function.on类型签名

+0

'( - >)'是右联合的,所以'(b - > b - > c) - >(a - > b) - > a - > a - > c'相当于'(b - > b - > c) - >(a - > b) - >(a - > a - > c)'。最后注意'a - > a - > c'的圆括号。 – 4castle

+0

它等于'on(*)f x y = f x * f y'。 – chi

回答

1

函数类型的Haskell箭头隐藏了一个简单但聪明的想法。您必须将->视为运营商,例如+-,但对于类型。它有两种类型作为参数,并给你一个由函数组成的新类型。因此,在

Int -> String 

你有类型IntString,你从一个Int得到一个函数的字符串。

就像任何其他操作符一样,您需要一条规则来链接它们。如果你想到-,这是什么意思?

10 - 6 - 4 

这是否意味着(10 - 6) - 4 = 0,还是意味着10 - (6 - 4) = 8?答案是第一个,这就是为什么我们说-是“左联合”。

->运算符是右结合的,所以

foo :: Int -> String -> String 

实际上意味着

foo :: Int -> (String -> String) 

想想这意味着什么。这意味着foo不接受2个参数并返回String类型的结果,它实际上需要1个参数(Int)并返回一个新函数,该函数接受第二个参数(String)并返回最终的String

功能应用程序的工作方式相同,除了左关联。所以

FOO 15 “维布勒”

实际上意味着

(FOO 15) “维布勒”

foo所以施加到15并返回一个新的功能,然后将其施加到"wibble"

这导致了一个巧妙的诀窍:当你调用一个函数时(而不是像所有其他编程语言一样),不必提供所有参数,只需提供第一个或前几个,然后取回一个期望剩下的参数的新函数。

这就是on发生的情况。我将使用一个更具体的版本,其中'f'被'长度'取代。

(*)on长度

你给on它的前两个参数。其结果是预计另外两个新功能。在类型,

on :: (b -> b -> c) -> (a -> b) -> a -> a -> c 

在这种情况下(*)具有类型Num n => n -> n -> n(我用不同的字母,使这个容易混淆),从而与第一个参数on的类型匹配,因此导致的结论是,如果b类型被替换为n,则类型c必须也是,并且也必须是Num实例。因此length必须返回一些数字类型。碰巧length的类型是[d] -> Int,并且IntNum的一个实例,因此可以解决。所以在这个结尾你得到:

(*) `on` length :: [d] -> [d] -> Int 
3

我的解释是,它有四个参数

所有的Haskell函数一个参数。其中一些只是返回其他功能。

查看on签名的最佳方式是作为高阶函数:(b -> b -> c) -> (a -> b) -> (a -> a -> c)。这说“如果你给我一个二进制运算符,需要b s并给出c和从a s得到b s,我会给你一个二进制运算符,它需要a s并给出c”。你可以在定义中看到:

(*) `on` f = \x y -> f x * f y