为什么 (++) 既可以用于前缀,也可以使用 map 进行追加



我目前正在开始使用Haskell(阅读Learn Yourself a Haskell),并遇到了类似于以下内容的行:

map (++"!") ["a", "b"] -- ["a!", "b!"]
map ("!"++) ["a", "b"] -- ["!a", "!b"]

为什么这是可能的,或者它是如何工作的?我无法对其他非交换运算做同样的事情,比如除法:

map (3/) [1..3]   -- [3.0,1.5,1.0]
map ((/)3) [1..3] -- [3.0,1.5,1.0]
map (3(/)) [1..3] -- error

我觉得我在这里错过了一些东西,但是map的实现并没有给我任何提示。

此代码无效:

map (3(/)) [1..3]

(/)是前缀函数,但您将其用作中缀。编译器在您尝试函数3(没有参数的函数)时看到它,(/)添加为参数。

/是中缀功能。因此,您可以执行以下操作:

map ( / 3) [1..3]   -- [0.3333333333333333,0.6666666666666666,1.0]
map (3 / ) [1..3]   -- [3.0,1.5,1.0]

这与map完全无关;map的参数可以是任何函数。

要了解您传递的功能,请查看此 GHCi 会话:

Prelude> :t (++"!")
(++"!") :: [Char] -> [Char]
Prelude> (++"!") "Hello"
"Hello!"
Prelude> ("!"++) "Hello"
"!Hello"
Prelude> :t ("!"++)
("!"++) :: [Char] -> [Char]

这里发生的是操作部分的句法思想(Haskell报告,第3.4节),可以理解为:

(x •) == (y. x • y)
(• x) == (y. y • x)

其中可以是任何操作,如++*甚至是有趣的自定义运算符,如^_^

如果一个函数在括号中声明:(++) :: [a] -> [a] -> [a],它可以与它们一起使用,也可以不使用它们。如果不带括号使用,它们必须出现在参数之间:"!" ++ "?" ,但使用括号,它们就像普通函数一样:(++) "!" "?"

Haskell允许函数的"部分应用",因此("!"++)(++) "!"x -> (++) "!" x相同,(++"?")x -> (++) x "?"相同。("部分应用"用引号引起来,因为Haskell中的函数总是只有一个参数,所以应用不再是"部分"的;在其他语言中(++)将被视为两个参数的函数,所以当只应用一个参数时,该函数被视为部分应用 - 从这个意义上说,查看("!++) 作为部分应用 (++))

您的第二个示例是使用 (/) 的有效方式,但如果使用 (/),它实际上不再是中缀函数,因此尝试在函数名称之前将第一个参数指定为 (/) 时会出现错误:3(/) 。如果删除括号,它仍然有效:(3 /)((/) 3)(x -> (/) 3 x)(x -> 3 / x)相同

相关内容

最新更新