Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/gwt/3.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_Functional Programming - Fatal编程技术网

Function Haskell-函数中的冗余部分

Function Haskell-函数中的冗余部分,function,haskell,functional-programming,Function,Haskell,Functional Programming,我有一个复杂的Haskell函数: j :: [Int] j = ((\f x -> map x) (\y -> 3 + y) (\z -> 2*z)) [1,2,3] f x = x + 2 我猜(\y->3+y)(\z->2*z)将更改为(\w->3+2*w),并与f一起打印出列表[5,7,9] 当我向ghci查询时,我得到了[2,4,6] 问题:这里的(\y->3+y)是多余的表达式吗?如果是这样,原因是什么?这是因为它反过来,那就是你首先将(\f x->map x)

我有一个复杂的
Haskell
函数:

j :: [Int]
j = ((\f x -> map x) (\y -> 3 + y) (\z -> 2*z)) [1,2,3]
f x = x + 2
我猜
(\y->3+y)(\z->2*z)
将更改为
(\w->3+2*w)
,并与
f
一起打印出列表
[5,7,9]

当我向ghci查询时,我得到了
[2,4,6]


问题:这里的
(\y->3+y)
是多余的表达式吗?如果是这样,原因是什么?

这是因为它反过来,那就是你首先将
(\f x->map x)
应用到
(\y->3+y)
。但是

(\f x -> map x) something g
变成

let f = something; x = g in map x
这最后是

map g
因此,
something
不会出现在结果表达式中,因为
f
没有在箭头的任何位置提及

如果我没弄错的话,你想

(\f x -> map (f . x))
附加说明:从你的论证来看,你似乎还没有掌握beta降低的原理

例如,即使表达式会像您所想的那样应用:

(\y -> 3 + y) (\z -> 2*z)
结果将是

3 + (\z -> 2*z)

不,这是否有意义值得怀疑,然而,这是beta缩减的工作方式:它给出了从箭头开始的部分,其中每个参数的出现都被实际参数替换。

这是因为它反过来,也就是说,您首先将
(\f x->map x)
应用到
(\y->3+y)
。但是

(\f x -> map x) something g
变成

let f = something; x = g in map x
这最后是

map g
因此,
something
不会出现在结果表达式中,因为
f
没有在箭头的任何位置提及

如果我没弄错的话,你想

(\f x -> map (f . x))
附加说明:从你的论证来看,你似乎还没有掌握beta降低的原理

例如,即使表达式会像您所想的那样应用:

(\y -> 3 + y) (\z -> 2*z)
结果将是

3 + (\z -> 2*z)

不,这是否有意义值得怀疑,然而,这是beta约化的工作方式:它给出了从箭头开始的部分,其中每个参数的出现都被实际参数替换。

我认为您在函数设计中的某个地方出错了,但我将向您解释这里的机制。如果你仍然无法理解,请留下详细解释

快速回答:计算表达式 您可能会看到,当Haskell计算
(\f x->map x)(\y->3+y)
(这是因为函数应用程序是从左到右计算的)时,会进行替换
f:=(\y->3+y)
,但是
f
不会出现在函数中的任何地方,因此它只是变成
(\x->map x)

详细答案:左(和右)关联运算符 在Haskell中,我们说函数应用程序是左关联的。也就是说,当我们编写函数应用程序时,它的计算如下:

function arg1 arg2 arg3 = ((function arg1) arg2) arg3
无论参数的类型是什么。这称为左关联,因为括号始终位于左侧

您似乎期望您的表情表现如下:

  (\f x -> map x) (\y -> 3 + y) (\z -> 2*z)
= (\f x -> map x) ((\y -> 3 + y) (\z -> 2*z)) -- Incorrect
  (\f x -> map x) (\y -> 3 + y) (\z -> 2*z)
= ((\f x -> map x) (\y -> 3 + y)) (\z -> 2*z)
= (\x -> map x) (\z -> 2*z)                   -- Correct!
但是,正如我们所看到的,函数与左关联,而不是与您假设的右关联,因此您的表达式在Haskell看来是这样的:

  (\f x -> map x) (\y -> 3 + y) (\z -> 2*z)
= (\f x -> map x) ((\y -> 3 + y) (\z -> 2*z)) -- Incorrect
  (\f x -> map x) (\y -> 3 + y) (\z -> 2*z)
= ((\f x -> map x) (\y -> 3 + y)) (\z -> 2*z)
= (\x -> map x) (\z -> 2*z)                   -- Correct!
请注意,我为排序计算而放的括号位于左侧,而不是右侧

然而,Haskell定义了一个非常有用的右关联函数应用操作符,即
($)::(a->b)->a->b
。您可以像这样重新编写表达式,以获得您似乎期望的结果

  (\f x -> map x) $ (\y -> 3 + y) (\z -> 2*z)
= (\f x -> map x) $ ((\y -> 3 + y) (\z -> 2*z)) -- Correct, though nonsensical.
但是,正如您所注意到的,f仍然没有在
(\f x->map x)
中引用,因此被完全忽略。我不确定你做这个函数的目的是什么

进一步问题:Lambda表达式和组合 我意识到另一个问题可能是您对lambda表达式的理解。考虑这个函数:

j :: [Int]
j = ((\f x -> map x) (\y -> 3 + y) (\z -> 2*z)) [1,2,3]
f x = x + 2
我们可以将其改写为lambda表达式,如下所示:

f = \x -> x+2
但是,如果我们有两个论点呢?我们就是这样做的:

g x y = x + y

g = \x -> (\y -> x+y)
Haskell对多个参数建模的方式称为。您可以看到,该函数实际上返回另一个函数,然后该函数返回一个函数,该函数最终返回它应该具有的内容。但是,这种表示法又长又麻烦,因此Haskell提供了一种替代方法:

g = \x y -> x + y
这看起来可能有所不同,但事实上,它是与以前完全相同的表达式的语法糖。现在,看看您的第一个lambda表达式:

\f x -> map x = \f -> (\x -> map x)
您可以看到,函数中根本没有引用参数f,因此如果我对其应用了一些东西:

  (\f x -> map x) foo
= (\f -> (\x -> map x)) foo
= \x -> map x
这就是你的
(\y->3+y)
被忽略的原因;实际上,您还没有在函数中使用它

此外,您希望表达式
(\y->3+y)(\z->2*z)
的计算结果为
\w->3+2*w
。事实并非如此。左边的lambda用
(\z->2*z)
替换了
y
的每一次出现,因此结果是完全没有意义的
3+(\z->2*z)
。你怎么给一个数字加上一个函数

你要找的是我们在Haskell中有一个操作符,即
(::(b->c)->(a->b)->(a->c)
,它可以帮助你解决这个问题。它在左侧和右侧接受一个函数,并创建一个新函数,将这些函数“管道化”到彼此中。也就是说:

(\y -> 3 + y) . (\z -> 2*z) = \w -> 3 + 2*w
这就是你要找的

结论:正确表达 我想你想要的表达方式是:

j = ( (\x -> map x) $ (\y -> 3 + y) . (\z -> 2*z) ) [1,2,3]
这相当于说:

j = map (\w -> 3 + 2*w) [1,2,3]

由于您似乎对Haskell的更基本的部分有很多问题,我推荐一本经典的入门书,

我认为您在函数的设计中有些地方出了问题,但我将向您解释这里的机制。如果你仍然无法理解,请留下详细解释

快速回答:计算表达式 您可能会看到,当Haskell计算
(\f x->map x)(\y->3+y)