为什么即使缺少参数,这个功能也能正常工作?

时间:2017-04-06 11:16:39

标签: haskell

我正在尝试理解以下代码:

import Data.Char (ord)

encodeInteger :: String -> Integer
encodeInteger = read . concatMap ch
    where ch c = show (ord c)

但是当encodeInteger被定义为接受字符串的函数时,我不知道这是如何工作的,但在第二行中,该函数是在没有该字符串参数的情况下实现的。

此外,concatMap(根据hoogle)采用函数和列表,但仅提供函数ch

为什么这段代码仍然有效?这个论点是否神奇地传递了?它与currying有关吗?

编辑:为什么不能像这样改变它:

encodeInteger :: String -> Integer
encodeInteger a = read . concatMap ch a
    where ch c = show (ord c)

2 个答案:

答案 0 :(得分:4)

基本上定义一个函数

f = g

与定义函数

相同
f x = g x

在您的具体情况下,您可以使用

encodeInteger a = (read . concatMap ch) a

定义你的功能。需要括号,否则将其解析为

encodeInteger a = (read) . (concatMap ch a)

concatMap ch a不是函数,无法编写。你最多可以写

encodeInteger a = read (concatMap ch a)
-- or
encodeInteger a = read $ concatMap ch a

关于"为什么concatMap ch只接受一个参数?"。这是一个部分应用程序,在Haskell中非常常见。如果你有

f x y z = x+y+z

你可以用较少的参数调用f,并获得剩余参数的函数作为结果。例如,f 1 2是执行z并返回1+2+z的功能。

具体地说,由于Currying,没有一个函数可以采用两个或更多的参数。每个函数总是只有一个参数。当你有像

这样的功能时
foo :: Int -> Bool -> String

然后foo接受一个参数Int。它返回一个函数,它取Bool并最终返回String。您可以通过编写

来形象化
foo :: Int -> (Bool -> String)

无论如何,如果你查看currying和部分应用,你会发现很多例子。

答案 1 :(得分:3)

encodeInteger :: String -> Integer
encodeInteger = read.concatMap (\char -> show $ ord char)

左侧的encodeInteger(LHS)" ="是一个名字;它指的是" ="的右侧功能(RHS)。两者都具有函数类型:String -> Integer。两者都取一个字符列表并生成一个整数。 Haskell使我们能够表达这样的函数相等而不指定形式参数(称为point-free的样式)。

现在,让我们来看看RHS。 (。)运算符一起组成两个函数。组合函数从concatMap获取一个字符串作为其输入,并产生一个来自read的整数作为组合函数的输出。

concatMap本身需要2个输入,但我们需要省略第二个输入的组合函数,这需要一个字符串作为输入。我们通过部分应用concatMap来实现这一点,仅包括其第一个参数。