"const id"的行为

man*_*ang 35 haskell

我正在研究99个Haskell问题,并找到了一个解决方案,用于查找列表的最后一个元素:

  myLast = foldr1 (const id)
Run Code Online (Sandbox Code Playgroud)

类型const就是a -> b -> a但的const idb -> a -> a
有啥这里的魔力?

Aar*_*aid 43

类型idc->c; 它只返回它给出的相同的东西.

类型consta->b->a.在const id,a变成c->c,所以在这种情况下const的类型变为:

(c->c) -> b -> (c->c)
Run Code Online (Sandbox Code Playgroud)

既然你已经应用了这个const函数,即你已经传递id给它,那么你就可以了b -> (c->c).

PS:const const idis a->b->a的类型和const const const idis 的类型b->a->a等等!

  • 当然,`ap`和`const`是计算任何东西所需的唯一两个函数.(那是读者monad的'ap`.) (4认同)
  • 还有`id = ap const const`. (3认同)

Apo*_*isp 23

没有魔法.定义const是:

const :: a -> b -> a
const x y = x
Run Code Online (Sandbox Code Playgroud)

而定义id是:

id :: a -> a
id x = x
Run Code Online (Sandbox Code Playgroud)

所以,这const id\y -> id一个永远返回的函数id.如果id是,\x -> x那么const id必须是相同的\y -> \x -> x.因此,它有类型b -> (a -> a).

const id也可以写flip const.由于constIS \x -> \y -> x,然后flip const取参数以相反的顺序,\y -> \x -> x,这是相同的const id.


小智 7

以下是我对其工作原理的理解.

这是我能想到的最简单的解释,我试图(故意)避免任何可能混淆的概念或单词.

要记住的一个重要概念是部分应用.

我理解这一点的方法是,在Haskell中我们可以将函数的一个参数"修复"为已知值,所以现在该函数接受一个较少的参数.

回顾:const的类型是:

const :: a -> b -> a
Run Code Online (Sandbox Code Playgroud)

作为一个更简单的例子,让我们将第一个参数"修复"为(+)

let f = const (+)
Run Code Online (Sandbox Code Playgroud)

现在我们已经修复了const的第一个参数,"f"是一个只接受单个参数的函数.但是因为const总是返回它的第一个参数,我们已经修复了它,这意味着我们传递给"f"的任何东西都将被忽略,它将始终返回函数"+".

例如,以下所有将给出5,因为f将始终返回函数"+",而不管它作为第一个参数接收到什么,并且函数"+"将在2和3上运行:

f “aaa”        2 3
f  904212      2 3
f  undefined   2 3
Run Code Online (Sandbox Code Playgroud)

f的类型是:

f :: b -> Integer -> Integer -> Integer
Run Code Online (Sandbox Code Playgroud)

注意,"b"可以是任何东西,如上所示.

现在对于有问题的实际功能:

g = const id
Run Code Online (Sandbox Code Playgroud)

这意味着我们将id"固定"为第一个参数,如上所述,"g"忽略其第一个参数并返回函数"id".在Haskell中,我们可以继续前进并为"id"提供额外的参数,就像我们对上面的(+)所做的那样,例如所有这些都将返回42:

g  “aaa”     42
g  undefined 42
Run Code Online (Sandbox Code Playgroud)

所以"g"是接受两个参数的函数,并且总是返回第二个参数,所以它的类型是:

g = const id :: b -> a -> a
Run Code Online (Sandbox Code Playgroud)

但是等一下,我只是在那里做了一个巨大的飞跃.不应该是这种类型:

b -> (a -> a) 
Run Code Online (Sandbox Code Playgroud)

既然我们只是说我们接受任何东西并返回"id"?

嗯,是的,除了在Haskell中,这些括号可以省略.
它也有意义,因为你可以立即提供所需的额外参数的"id"函数(如上面的"const(+)"示例).


小智 6

我最终理解这一点的唯一方法是想象 Haskell 在计算像这样的表达式时所采取的步骤顺序const id 1 2。首先考虑这些陈述:

在 Haskell 中,所有函数都被认为是柯里化的:也就是说,Haskell 中的所有函数都只接受一个参数。1

但函数式应用与左侧关联:fxy 实际上是 (fx) y。1

考虑到这一点,并从上面看到const需要两个参数和id一个参数,我们可以看到以下步骤:

const id 1 2   -- Haskell evaluates 'const id' and returns a function (we can call it
               -- 'constId') which accepts one argument and always returns 'id'

constId 1 2    -- Haskell now evaluates 'constId 1', which as expected just returns 'id'

id 2           -- 'id' is now applied to 2, which just returns '2'

2              -- final result
Run Code Online (Sandbox Code Playgroud)

免责声明:我是 Haskell 的新手。