Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Function Haskell:带函数参数的箭头优先级_Function_Haskell_Recursion_Arguments_Operator Precedence - Fatal编程技术网

Function Haskell:带函数参数的箭头优先级

Function Haskell:带函数参数的箭头优先级,function,haskell,recursion,arguments,operator-precedence,Function,Haskell,Recursion,Arguments,Operator Precedence,我是一个相对有经验的Haskell程序员,有几个小时的经验,所以答案可能是显而易见的 在观看了Haskell的一段经历后,当Simon解释append(++)函数如何使用其参数时,我迷路了 所以 首先,他说,(++)::[a]->[a]->[a]可以理解为一个函数,它获取两个列表作为参数,并在最后一个箭头后返回一个列表)。但是,他补充说,实际上,类似的情况会发生:(++):[a]->([a]->[a]),函数只接受一个参数并返回一个函数 我不确定返回的函数闭包如何获得第一个列表,因为它也需要一个

我是一个相对有经验的Haskell程序员,有几个小时的经验,所以答案可能是显而易见的

在观看了Haskell的一段经历后,当Simon解释append
(++)
函数如何使用其参数时,我迷路了

所以

首先,他说,
(++)::[a]->[a]->[a]
可以理解为一个函数,它获取两个列表作为参数,并在最后一个箭头后返回一个列表)。但是,他补充说,实际上,类似的情况会发生:
(++):[a]->([a]->[a])
,函数只接受一个参数并返回一个函数

我不确定返回的函数闭包如何获得第一个列表,因为它也需要一个参数

在演示的下一张幻灯片上,我们有以下实现:

(++) :: [a] -> [a] -> [a]

[]     ++ ys = ys
(x:xs) ++ ys = x : (xs ++ ys)
如果我认为(++)接收两个参数并返回一个列表,那么这段代码以及递归就足够清楚了

如果我们认为<代码>(++)<代码>只接收一个参数并返回一个列表,那么<代码> ys>代码>来自哪里?返回的函数在哪里?

您对如何工作感到困惑。 考虑
(++)
的以下函数定义

接受两个参数,生成一个列表:

(++) :: [a] -> [a] -> [a]
[]     ++ ys = ys
(x:xs) ++ ys = x : (xs ++ ys)
(++) :: [a] -> ([a] -> [a])
(++) []     = id
(++) (x:xs) = (x :) . (xs ++)
接受一个参数,生成一个函数接受一个列表并生成一个列表:

(++) :: [a] -> [a] -> [a]
[]     ++ ys = ys
(x:xs) ++ ys = x : (xs ++ ys)
(++) :: [a] -> ([a] -> [a])
(++) []     = id
(++) (x:xs) = (x :) . (xs ++)
如果仔细观察,这些函数将始终生成相同的输出。通过删除第二个参数,我们将返回类型从
[a]
更改为
[a]->[a]

  • 如果我们向
    (++)
    提供两个参数,则得到类型为
    [a]
  • 如果我们只提供一个参数,则得到类型为
    [a]->[a]

这就是所谓的函数咖喱。我们不需要为具有多个参数的函数提供所有参数。如果我们提供的参数少于参数总数,那么我们得到的不是一个“具体”的结果(
[a]
),而是一个可以接受其余参数的函数(
[a]->[a]
)。

理解这一点的诀窍是所有haskell函数最多只接受一个参数,只是类型签名和语法糖中的隐式括号使它看起来好像有更多的参数。以
++
为例,以下转换都是等效的

xs ++ ys = ...
(++) xs ys = ...
(++) xs = \ys -> ...
(++) = \xs -> (\ys -> ...)
(++) = \xs ys -> ...
另一个快速示例:

doubleList :: [Int] -> [Int]
doubleList = map (*2)
这里我们有一个单参数的函数
doubleList
,没有任何显式参数。这就相当于写作

doubleList x = map (*2) x
或以下任何一项

doubleList = \x -> map (*2) x
doubleList = \x -> map (\y -> y * 2) x
doubleList x = map (\y -> y * 2) x
doubleList = map (\y -> y * 2)
双重列表的第一个定义是用通常称为无点表示法编写的,之所以称之为无点表示法,是因为在支持它的数学理论中,参数被称为“点”,因此无点表示法是“无参数”

一个更复杂的例子:

func = \x y z -> x * y + z
func = \x -> \y z -> x * y + z
func x = \y z -> x * y + z
func x = \y -> \z -> x * y + z
func x y = \z -> x * y + z
func x y z = x * y + z
现在,如果我们想完全删除对参数的所有引用,我们可以使用执行函数组合的
运算符:

func x y z = (+) (x * y) z    -- Make the + prefix
func x y = (+) (x * y)        -- Now z becomes implicit
func x y = (+) ((*) x y)      -- Make the * prefix
func x y = ((+) . ((*) x)) y  -- Rewrite using composition
func x = (+) . ((*) x)        -- Now y becomes implicit
func x = (.) (+) ((*) x)      -- Make the . prefix
func x = ((.) (+)) ((*) x)    -- Make implicit parens explicit
func x = (((.) (+)) . (*)) x  -- Rewrite using composition
func = ((.) (+)) . (*)        -- Now x becomes implicit
func = (.) ((.) (+)) (*)      -- Make the . prefix

因此,正如您所看到的,有许多不同的方法可以使用不同数量的显式“参数”来编写特定函数,其中一些非常可读(即
func x y z=x*y+z
),而另一些方法只是一堆毫无意义的符号(即
func=()(+)(*)

也许这会有所帮助。首先,让我们不用运算符符号来编写它,这可能会让人困惑

append :: [a] -> [a] -> [a]
append [] ys = ys
append (x:xs) ys = x : append xs ys
我们可以一次应用一个参数:

appendEmpty :: [a] -> [a]
appendEmpty = append []
我们也可以写出来

appendEmpty ys = ys
appendOne ys = 1 : append [] ys
从第一个方程式

如果我们应用非空的第一个参数:

-- Since 1 is an Int, the type gets specialized.
appendOne :: [Int] -> [Int]
appendOne = append (1:[])
我们本可以写下同样的内容

appendEmpty ys = ys
appendOne ys = 1 : append [] ys

从第二个等式开始。

查找currying:在大多数函数式编程语言中,不存在函数包含多个参数的情况。“二进制函数”是一个从技术上讲不正确的术语,用于表示接受一个参数(第一个)并返回一个函数的函数。此返回函数接受一个参数(“第二个”参数),最后返回结果。例如,
(++)[1,2]
是一个可以应用于
[4,5]
以生成
[1,2,4,5]
的函数。好吧,我可以认为函数是lambda函数的别名。未传递参数,但按以下顺序填充/替换:
add=\x y->x+y
add3 4
(\x y->x+y)3 4
,但我了解到无点样式是最受欢迎的样式。有没有办法用高阶函数编写最后一行的
func=
行?@D.Naesuko无点样式只有在看起来更清晰时才是首选。这只是删除一个函数参数时的情况,很少是删除多个函数参数时的情况。