Подтвердить что ты не робот

Поведение "const id"

Я работаю над вопросами 99 Haskell и увидел решение для поиска последнего элемента списка:

  myLast = foldr1 (const id)

тип const равен a -> b -> a, а const id - b -> a -> a
так что здесь волшебство?

4b9b3361

Ответ 1

Тип id - c->c; он просто возвращает то же самое, что и ему.

Тип const - a->b->a. В const id, a становится c->c, поэтому тип const в этом случае становится:

(c->c) -> b -> (c->c)

Теперь, когда вы применили эту функцию const, т.е. вы передали ей id, вы остаетесь с b -> (c->c).

PS: Тип const const id равен a->b->a, а тип const const const id равен b->a->a и т.д.!

Ответ 2

Никакой магии. Определение const:

const :: a -> b -> a
const x y = x

И определение id:

id :: a -> a
id x = x

Итак const id - это просто \y -> id, функция, которая всегда возвращает id. И если id просто \x -> x, то const id должен быть таким же, как \y -> \x -> x. Эрго, он имеет тип b -> (a -> a).

const id также можно записать flip const. Поскольку const есть \x -> \y -> x, то flip const принимает аргументы в обратном порядке, \y -> \x -> x, что совпадает с const id.

Ответ 3

Вот мое понимание того, как это работает.

Это самое простое объяснение, о котором я мог думать, я попытался (специально) избежать любых потенциально запутанных понятий или слов.

Важное понятие, которое следует иметь в виду, - это частичное применение.

То, как я это понимаю, заключается в том, что в Haskell мы можем "исправить" один из параметров функции до известного значения, поэтому теперь функция принимает один меньший параметр.

Recap: тип const:

const :: a -> b -> a

В качестве более простого примера, пусть "исправить" первый параметр будет (+)

let f = const (+)

Теперь, когда мы зафиксировали первый параметр const, "f" - это функция, которая принимает только один параметр. Но поскольку const всегда возвращает свой первый параметр, который мы исправили, это означает, что все, что мы передаем в "f", будет проигнорировано, и оно всегда будет возвращать функцию "+" .

В качестве примера все следующие будут давать 5, так как f всегда будет возвращать функцию "+" независимо от того, что она получила в качестве первого параметра, а функция "+" будет работать на 2 и 3:

f "aaa"        2 3
f  904212      2 3
f  undefined   2 3

Тип f:

f :: b -> Integer -> Integer -> Integer

Обратите внимание, что "b" может быть любым, как можно видеть выше.

Теперь для актуальной функции:

g = const id

Это означает, что мы "фиксировали" id как первый параметр, так же, как и выше, "g" игнорирует свой первый параметр и возвращает функцию "id". В Haskell мы можем продолжить и предоставить дополнительный параметр "id", как и мы (+) выше, так что, например, все они вернут 42:

g  "aaa"     42
g  undefined 42

Итак, "g" - это функция, принимающая два параметра и всегда возвращающая вторую, поэтому ее тип:

g = const id :: b -> a -> a

Но подождите минуту, я просто совершил гигантский прыжок. Не должен быть тип:

b -> (a -> a) 

так как мы только что сказали, что принимаем что угодно и возвращаем "id"?

Хорошо, да, кроме того, что в Haskell эти круглые скобки можно опустить.
Это также имеет смысл, поскольку вы можете сразу предоставить функцию "id" с дополнительным параметром, который ему нужен (как в примере "const (+)" выше).

Ответ 4

Единственный способ, которым я, наконец, понял это, - представить последовательность шагов, которые Haskell берет при оценке выражения типа const id 1 2. Сначала рассмотрим следующие утверждения:

В Haskell все функции считаются curried: То есть все функции в Haskell принимают только один аргумент. 1

Функциональное приложение, тем не менее, ассоциируется слева: f x y действительно (f x) 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

Отказ от ответственности: я новичок в Haskell.