$ 运算符将函数应用于参数。我们可以将您的示例重写为
replace :: Char -> Char -> [Char] -> [Char]
replace a b = map (\c -> if c == a then b else c)
实际上,Haskellers 经常使用$ 来避免括号。由于其他原因,它很少使用。
关于\c -> ...:这是一个匿名函数,也称为“lambda”。它代表以c 作为参数并返回... 部分的函数。在您的情况下,该函数接受c 并检查它是否等于a,在这种情况下它返回b,否则它返回c。我们可以在没有 lambda 的情况下重写代码,如下所示:
replace :: Char -> Char -> [Char] -> [Char]
replace a b = map myFun
where
myFun :: Char -> Char
myFun = \c -> if c == a then b else c
或者,将参数c移动到=的左边,如下:
replace :: Char -> Char -> [Char] -> [Char]
replace a b = map myFun
where
myFun :: Char -> Char
myFun c = if c == a then b else c
关于“缺少第三个参数”:Char -> Char -> [Char] -> [Char] 类型可以多种方式读取:
- 采用一个参数 (
Char) 并返回一个函数 (Char -> [Char] -> [Char]) 的函数类型
- 采用两个参数(
Char 和 Char)并返回一个函数([Char] -> [Char])的函数类型
- 采用三个参数(
Char、Char 和 [Char])并返回一个列表([Char])的函数类型
由于柯里化,所有这三种解释都是兼容的。确实,“两个参数”函数
foo :: A -> B -> B
foo x y = y
和功能
foo :: A -> B -> B
foo x = id -- id is the identity function B -> B
都是一样的。
在您的示例中,如果需要,您可以将缺失的参数添加到= 的两侧,如下所示:
replace :: Char -> Char -> [Char] -> [Char]
replace a b xs = map myFun xs
where
myFun :: Char -> Char
myFun c = if c == a then b else c
在这个展开的代码中,您可以看到map myFun xs 使用map(库函数)将myFun 应用于列表xs 的所有元素,并返回所有结果的列表。
这有效地实现了您想要的替换。
但是,不添加第三个参数,
replace :: Char -> Char -> [Char] -> [Char]
replace a b = map myFun
where ...
我们仍然可以将map myFun 解释为将函数myFun :: Char -> Char 转换为函数[Char] -> [Char]。如果我们将其解释为“两个参数”函数,后者确实是 replace 的返回类型。也就是说,replace 'a' 'b' 是函数[Char] -> [Char],它接受一个字符串并将其中的每个'a' 替换为'b'。