Haskell函数参数的顺序是否有意义? [英] Is there significance in the order of Haskell function parameters?

查看:75
本文介绍了Haskell函数参数的顺序是否有意义?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在学习Haskell,我注意到许多内置函数在顺序计数器中接受参数,这些参数直观地符合我的期望.例如:

replicate :: Int -> a -> [a]

如果我想复制7次两次,我会写replicate 2 7.但是当用英语大声读出时,函数调用感觉就像是在说重复2次,7次".如果我自己编写函数,则应该交换第一个和第二个参数,以使replicate 7 2读为"replicate 7,2 times".

当我经历 99 Haskell问题时,出现了一些其他示例.我必须编写一个函数:

dropEvery :: [a] -> Int -> [a]`

它将列表作为第一个参数,将Int作为第二个参数.直观地讲,我将标题写为dropEvery :: Int -> [a] -> [a],所以dropEvery 3 [1..100]读为:删除列表[1..100]中的每第三个元素.但是在问题的示例中,它看起来像是:dropEvery [1..100] 3." >

我也看到了其他我现在找不到的功能.出于实际原因,以这种方式编写函数是常见的还是仅在我脑海中?

解决方案

以这种方式编写函数的原因之一是因为它们的咖喱形式证明是有用的.

例如,考虑功能mapfilter:

map :: (a -> b) -> [a] -> [b]
filter :: (a -> Bool) -> [a] -> [a]

如果我想将偶数保留在列表中,然后将它们除以2,我可以写:

myfunc :: [Int] -> [Int]
myfunc as = map (`div` 2) (filter even as)

也可以这样写:

myfunc = map (`div` 2) . filter even
         \___ 2 ____/    \___ 1 ___/

将其设想为从右到左的管道:

  • 首先,我们保留偶数(第1步)
  • 然后我们将每个数字除以2(第2步)

.运算符at是将流水线段连接在一起的一种方式-类似于|运算符在Unix shell中的工作方式.

这都是可能的,因为mapfilter的list参数是这些函数的最后一个参数.

如果您使用以下签名写dropEvery:

dropEvery :: Int -> [a] -> [a]

然后我们可以将其包含在以下管道之一中,例如:

myfunc2 = dropEvery 3 . map (`div` 2) . filter even

I've been learning Haskell and I noticed that many of the built in functions accept parameters in an order counter intuitive to what I would expect. For example:

replicate :: Int -> a -> [a]

If I want to replicate 7 twice, I would write replicate 2 7. But when read out loud in English, the function call feels like it is saying "Replicate 2, 7 times". If I would have written the function myself, I would have swapped the first and second arguments so that replicate 7 2 would read "replicate 7, 2 times".

Some other examples appeared when I was going through 99 Haskell Problems. I had to write a function:

dropEvery :: [a] -> Int -> [a]`

It takes a list as its first argument and an Int as its second. Intuitively, I would have written the header as dropEvery :: Int -> [a] -> [a] so that dropEvery 3 [1..100] would read as: "drop every third element in the list [1..100]. But in the question's example, it would look like: dropEvery [1..100] 3.

I've also seen this with other functions that I cannot find right now. Is it common to write functions in such a way due to a practical reason or is this all just in my head?

解决方案

One of the reasons functions are written this way is because their curried forms turn out to be useful.

For example, consider the functions map and filter:

map :: (a -> b) -> [a] -> [b]
filter :: (a -> Bool) -> [a] -> [a]

If I wanted to keep the even numbers in a list and then divide them by 2, I could write:

myfunc :: [Int] -> [Int]
myfunc as = map (`div` 2) (filter even as)

which may also be written this way:

myfunc = map (`div` 2) . filter even
         \___ 2 ____/    \___ 1 ___/

Envision this as a pipeline going from right to left:

  • first we keep the even numbers (step 1)
  • then we divide each number by 2 (step 2)

The . operator at as a way of joining pipeline segments together - much like how the | operator works in the Unix shell.

This is all possible because the list argument for map and filter are the last parameters to those functions.

If you write your dropEvery with this signature:

dropEvery :: Int -> [a] -> [a]

then we can include it in one of these pipelines, e.g.:

myfunc2 = dropEvery 3 . map (`div` 2) . filter even

这篇关于Haskell函数参数的顺序是否有意义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆