我正在尝试理解以下代码:
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)
答案 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
来实现这一点,仅包括其第一个参数。