混淆了复合函数与haskell中的map

时间:2017-07-26 07:09:12

标签: haskell

 let f = map tail.lines
 f "fsdaf\nfdsf\n"

为什么会有效?

let f = map tail.tail.lines
f "fasdf\nfasdfdsfd\n"

我得到结果:

["asdfdsfd"]
let f = map (tail.tail).lines
f "fasdf\nfasdfdsfd\n"

我得到结果:

["sdf","sdfdsfd"]

我想知道haskell如何解析上面的代码。

2 个答案:

答案 0 :(得分:6)

让我们看看你的第一个例子:

let f = map tail.tail.lines
f "fasdf\nfasdfdsfd\n"

首先,lines将输入字符串分解为字符串数组:["fasdf","fasdfdsfd"]

现在,从右到左工作,tail放弃" head"列表:["fasdfdsfd"]

最后,map tail应用"尾部"列表中的每个元素:["asdfdsfd"]

你的第二个例子类似:

let f = map (tail.tail).lines
f "fasdf\nfasdfdsfd\n"

同样,您将输入字符串分解为字符串数组:["fasdf","fasdfdsfd"]

然而,现在,您正在创建复合函数(tail.tail)(删除列表中的#34; head"两次),并将其映射到列表中的每个元素。

因此,您删除每个字符串的前两个字符。

["sdf","sdfdsfd"]

您的示例都按预期工作。阅读有关haskell中的关联性和复合函数的内容,以便更多地了解它。

编辑:区别在于:

map tail (tail lines) vs map (tail.tail) lines

请记住,在Haskell中,函数是一等公民 - 您可以创建复合函数(例如:(+1).(+1))并执行其他不常见的操作(例如map列表中的函数)用其他语言。

答案 1 :(得分:1)

第一篇文章是完全正确的,但是因为你找到了更多的问题,这是我的尝试......

当您尝试理解此代码的作用时,了解函数的作用以及它们的应用顺序非常重要,所以让我们来看看:

lines :: String -> [String] --takes a String and returns a list of Strings
tail :: [a] -> [a] --takes a (nonempty) list and drops the head (a list containing the rest)
(.) :: (b -> c) -> (a -> b) -> a -> c --function composition

现在这很重要...函数组合是正确的关联,优先级为9(最高!)

map :: (a -> b) -> [a] -> [b] --applies (a -> b) to every element of [a]

现在代码:

let f = map tail.tail.lines

相当于

let f x = map tail ((tail.lines) $ x)

这意味着您将tail映射到tail结果lines的结果。这种行为是因为(.),以及函数应用程序在Haskell中是正确关联的。值得注意的是,(tail.lines)是部分函数应用的结果(正如您可以从(。)的类型签名中看到a缺失...因此它将返回一个函数需要a并返回c

在后面的例子中:

let f = map (tail.tail).lines

应用程序的顺序由括号改变...此版本相当于:

let f x = map (tail.tail) (lines $ x)

所以它会将tail.tail(放头两次)映射到lines的结果上。

关键是理解相关性。它确定在没有括号的情况下首先应用哪个函数,以及函数是否具有相同的优先级。

我希望这有助于您了解其中的差异。