简体   繁体   English

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

[英]Why isn't it necessary to provide a parameter in this function?

I'm fairly new to Haskell and this week I found this particular function in a couple of lecture slides. 我是Haskell的新手,本周我在几张幻灯片中找到了此特定功能。 I'm trying to understand why the following function doesn't need to include a parameter: 我试图了解为什么以下函数不需要包含参数:

-- 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

If I would call it like tails "thisisastring" then this would be a valid argument. 如果我将其称为tails "thisisastring"那么这将是一个有效的参数。 Isn't it necessary to provide a parameter, for example tails xs = ... . 不必提供参数,例如tails xs = ... All the other functions I seen before were in that fashion. 我以前看到的所有其他功能都是这种方式。

This is called point-free style (where "point" is a mathematical term that basically means "argument" here). 这称为无点样式(其中“点”是一个数学术语,在这里基本上表示“自变量”)。

Even tails xs = ... is just syntactic sugar for tails = \\xs -> ... , so all you need to do to convince yourself that tails is a function is to recognize that 即使是tails xs = ...也只是tails = \\xs -> ...语法糖,因此,要使自己相信tails是一个函数,您需要做的就是认识到

  1. reverse , map reverse , and inits are all functions: reversemap reverseinits都是函数:

    • map is a higher-order function; map是一个高阶函数; it takes one function as an argument and returns another function. 它使用一个函数作为参数,然后返回另一个函数。

    • map reverse is a function because map is applied to the function reverse . map reverse是一个函数,因为将map应用于reverse函数。

  2. The composition of two functions is another function (assume that the types match up so that we can focus on the result of each composition, instead of verify that each composition type-checks.) 两个函数的组合是另一个函数(假定类型匹配,以便我们可以专注于每个组合的结果,而不是验证每个组合的类型检查。)

Thus 从而

  • reverse . map reverse reverse . map reverse is a function, reverse . map reverse功能
  • so reverse . map reverse . inits 如此reverse . map reverse . inits reverse . map reverse . inits reverse . map reverse . inits is a function, reverse . map reverse . inits是一个功能,
  • and reverse . map reverse . inits . reverse reverse . map reverse . inits . reverse reverse . map reverse . inits . reverse reverse . map reverse . inits . reverse is a function. reverse . map reverse . inits . reverse是一种功能。

Since tails is assigned the value of reverse . map reverse . inits . reverse 由于为tails分配了reverse . map reverse . inits . reverse的值reverse . map reverse . inits . reverse reverse . map reverse . inits . reverse reverse . map reverse . inits . reverse , tails itself is also a function. reverse . map reverse . inits . reversetails本身也是一个功能。

The parameter is implicit. 该参数是隐式的。 Or to put it differently, reverse . map reverse . inits . reverse 或者换句话说, reverse . map reverse . inits . reverse reverse . map reverse . inits . reverse reverse . map reverse . inits . reverse evaluates to a function of type [a] -> [[a]] . reverse . map reverse . inits . reverse求值为类型[a] -> [[a]]的函数。

Consider a simpler example: 考虑一个更简单的示例:

double_impl x = x * 2
double = double_impl

The type of double here is the same type as double_impl , ie it takes one parameter of typeclass Num : 在这里, double的类型与double_impl相同,即,它采用double_impl Num一个参数:

main = do 
  print $ double_impl 5
  print $ double 5

-- Out: 10
-- Out: 10

We can see that tails is a function, by checking it's type. 通过检查其类型,我们可以看到tails是一个函数。

To compute its type, we begin by writing down the types of all the intermediate functions in the composition. 为了计算其类型,我们首先写下组合中所有中间函数的类型。 Note that we use new type variables for each ocurrence of a function. 注意,对于函数的每次出现,我们都使用新的类型变量。

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

Now we have map reverse has type [[e]] -> [[e]] since we get c=d=[e] for some type e from comparing the expressions 现在我们得到map reverse类型为[[e]] -> [[e]]因为通过比较表达式,对于某些类型e我们得到c=d=[e]

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

Hence the last two intermediates have types 因此,最后两个中间体具有类型

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

Now we start trying to match up types. 现在我们开始尝试匹配类型。 Let me emphasize first that obviously THESE ARE NOT REAL TYPES! 首先让我强调一下,这些显然不是真实类型! (sorry for the all caps, but I don't want anyone to miss that.) (对不起,大写,但我不想让任何人错过。)

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]]

Then for the next composition: 然后进行下一个合成:

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]]

Finally, we have 最后,我们有

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]]

Since tails has the type [a] -> [[a]] , it must be a function that accepts a list of a s as it's argument and returns a list of lists of a s. 由于tails有型[a] -> [[a]] ,它必须接受列表的功能, a S作为它的参数,返回的清单列表a秒。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM