为什么没有必要在这个函数中提供参数?

时间:2016-07-28 18:13:52

标签: haskell pointfree

我对Haskell相当新,本周我在几个演讲幻灯片中找到了这个特殊的功能。我试图理解为什么以下函数不需要包含参数:

-- Return all final segments of the argument, longest first 
-- (horrible runtime complexity, used here for illustration purposes only)
tails :: [a] -> [[a]]
tails = reverse . map reverse . inits . reverse

如果我将其称为tails "thisisastring",那么这将是一个有效的论点。是否有必要提供参数,例如tails xs = ...。我之前见过的所有其他功能都是那种方式。

3 个答案:

答案 0 :(得分:4)

这称为无点样式(其中“点”是一个数学术语,在这里基本上意味着“参数”)。

即使tails xs = ...只是tails = \xs -> ...的语法糖,所以你需要做的就是让自己说服tails是一个函数就是认识到

  1. reversemap reverseinits都是功能:

    • map是一个高阶函数;它将一个函数作为参数并返回另一个函数。

    • map reverse是一个函数,因为map已应用于函数reverse

  2. 两个函数的组合是另一个函数(假设类型匹配,以便我们可以专注于每个组合的结果,而不是验证每个组合类型检查。)
  3. 因此

    • reverse . map reverse是一个函数,
    • 所以reverse . map reverse . inits是一个函数,
    • reverse . map reverse . inits . reverse是一个函数。

    由于tails的值为reverse . map reverse . inits . reversetails本身也是一个函数。

答案 1 :(得分:3)

该参数是隐式的。或者换句话说,[a] -> [[a]]评估为double_impl x = x * 2 double = double_impl 类型的函数。

考虑一个更简单的例子:

double

此处double_impl的类型与Num的类型相同,即它需要一个类型main = do print $ double_impl 5 print $ double 5 -- Out: 10 -- Out: 10 的参数:

$('#yourTextBoxId').live('change keyup paste', function(){
    if ($('#yourTextBoxId').val().length > 11) {
        $('#yourTextBoxId').val($('#yourTextBoxId').val().substr(0,10));
    }
});

答案 2 :(得分:2)

我们可以看到tails是一个函数,通过检查它的类型。

要计算其类型,我们首先写下合成中所有中间函数的类型。请注意,我们为函数的每个事件使用新的类型变量。

reverse :: [a] -> [a]
inits :: [b] -> [[b]]
map :: (c -> d) -> [c] -> [d]

现在我们map reverse的类型为[[e]] -> [[e]],因为我们通过比较表达式{/ 1>获得某些类型c=d=[e]的{​​{1}}

e

因此最后两个中间体具有类型

reverse :: c -> d  -- for some c and d
reverse :: [e] -> [e] -- for some e

现在我们开始尝试匹配类型。首先我要强调,显然这些并不是真正的类型! (对不起,所有的上限,但我不希望任何人错过。)

map reverse :: [[e]] -> [[e]]
reverse :: [f] -> [f]

然后是下一个作文:

inits . reverse :: [a] -*- [a] = [b] -*> [[b]]
-- I'm using a -*- b -*> c to denote the type a -> c obtained by
-- composing a function of type a -> b with one of type b -> c.
-- The *s are to break the double dashes up,
-- so they aren't parsed as a comment.
-- Anyway, looking at this type, we see
-- we must have [a] = [b], so a = b
-- we can rewrite the type of inits . reverse as
inits . reverse :: [a] -> [[a]]

最后,我们有

map reverse . inits . reverse :: [a] -*- [[a]] = [[e]] -*> [[e]]
-- again, we have [[a]] = [[e]], so e = a, and we have
map reverse . inits . reverse :: [a] -> [[a]]

由于reverse . map reverse . inits . reverse :: [a] -*- [[a]] = [f] -*> [f] -- This time we have [[a]] = [f], so we must have f = [a], so the type -- of the final composition is tails = reverse . map reverse . inits . reverse :: [a] -> [[a]] 的类型为tails,因此它必须是一个接受[a] -> [[a]]列表作为其参数的函数,并返回a个列表的列表