Как работает функция, которая увеличивает значение? - PullRequest
0 голосов
/ 27 февраля 2019

Я пытаюсь выучить haskell после нескольких лет ООП.Я читаю Happy Haskell.Он предоставляет следующий код:

plus :: Int -> Int -> Int
plus x y = x + y

plus' :: Int -> Int -> Int
plus' = \x -> \y -> x + y

increment :: Int -> Int
increment = plus 1

increment' :: Int -> Int
increment' = (\x -> \y -> x + y) 1

Я понимаю, как работают плюсы и плюсы (они одинаковые, разный синтаксис).Но прироста я не получаю.

increment :: Int -> Int

означает, что он принимает int и возвращает int, верно?Но сразу после этого фактическая функция:

increment = plus 1

Вопрос:

Где происходит приращение целочисленного значения?Разве не должно быть x или что-то справа от знака =, чтобы обозначать целочисленное значение, которое функция принимает в качестве входных данных?Что-то вроде:

increment _ = plus 1 x

Редактировать: Кроме того, определение приращения не должно быть Int -> (Int -> Int), поскольку оно принимает int и передает его функции, которая принимает int и возвращает и int

Ответы [ 4 ]

0 голосов
/ 27 февраля 2019

Примеры plus и plus' поучительны.Вы видите, что последний, похоже, не имеет аргументов, по крайней мере, слева от знака равенства:

plus' :: Int -> Int -> Int
plus' = \x -> \y -> x + y

Давайте создадим еще одну пару версий приращения (я назову их после того, как "удар")- 1) на полпути к окончательным версиям, которые вы дали:

bump :: Int -> Int
bump y = 1 + y

bump' :: Int -> Int
bump' = \y -> 1 + y

Аналогия между этими двумя определениями аналогична описанной между plus и plus', поэтому они должны иметь смысл, включаяпоследний, даже если у него нет формальных аргументов в левой части знака равенства.

Теперь, ваше понимание bump', точно такое же понимание, которое вам нужно понять increment', как вы далиэто по твоему вопросу!Фактически, мы определяем bump' как равное чему-то, что точно равно increment'.

То есть (как мы вскоре увидим), правая часть *Определение 1019 *,

\y -> 1 + y

- это то, что равно

plus 1

Две нотации или выражения являются двумя синтаксическими способами определения "функции, которая принимает числои возвращает на единицу больше, чем оно. "

Но что делает их равными?! Ну, (как объяснили другие авторы) выражение plus 1 является частично примененным ,Компилятор, в некотором роде, знает, что plus требует два аргумента (он был объявлен таким образом в конце концов), и поэтому, когда он появляется здесь применительно только к одному аргументу, компилятор знает, что он все еще ожидает еще один.Он представляет это «ожидание», предоставляя вам функцию, говоря, что, если вы дадите еще один аргумент, будь то сейчас или позже, это сделает эту вещь полностью примененной, и программа фактически перейдет к телу функции plus (таким образом,вычисление x + y для двух приведенных аргументов: литерала 1 из выражения plus 1 и приведенного позже «еще одного» аргумента)

Ключевая часть радости и ценности Haskellдумает о функциях как о вещах самих по себе, которые можно передавать и очень гибко преобразовывать из одного в другое.Частичное применение - это просто способ преобразования одной вещи (функция с «слишком большим количеством аргументов», когда вы хотите зафиксировать значение дополнительных функций) в функцию «просто правильных многих».Вы можете передать частично примененную функцию интерфейсу, который ожидает определенное количество аргументов.Или вы можете просто захотеть определить несколько специализированных функций на основе одного общего определения (как мы можем определить общие plus и более конкретные функции, такие как plus 1 и plus 7).

0 голосов
/ 27 февраля 2019

Это потому, что все функции в Haskell неявно curried .Таким образом, нет различия между функцией, которая возвращает функцию, принимающую аргумент, и функцией, которая принимает два аргумента, возвращающих значение (оба имеют тип a -> a -> a).Поэтому вызов plus (или любой другой функции) с слишком малым количеством аргументов просто возвращает новую функцию с примененными уже заданными аргументами.В большинстве языков это будет ошибкой аргумента.См. Также стиль без точек .

Сигнатуры типа Haskell ассоциированы справа, поэтому a -> a -> a -> a эквивалентно a -> (a -> (a -> a)).

0 голосов
/ 27 февраля 2019

Частичное применение

В Haskell вы можете использовать каррирование и частичное применение функций.Взгляните на Haskell Wiki: Частичное приложение

В частности, если вы посмотрите на сигнатуру типа любой функции, нет реального различия между ее входами (аргументами) и ее выходами,и это потому, что на самом деле ваша функция plus :: Int -> Int -> Int является функцией, которая, когда ей присваивается Int, возвращает другую функцию, которая сама принимает оставшиеся аргументы и возвращает int: Int -> Int.Это называется частичное применение

Это означает, что когда вы вызываете increment = plus 1, вы говорите, что приращение равно - вспомните частичное применение - функции (возвращается plus 1), который сам принимает целое число и возвращает целое число.

Поскольку Haskell является функциональным языком программирования, все с равным является не присваиванием, а скорее определением, поэтому простой способ понять частичное применение действительночтобы следовать за знаками равенства:

increment = plus 1 = 
            plus 1 y = 1 + y

Основное использование

Как видите, частичное применение может использоваться для определения более специфических функций, таких как добавление 1 к числу, которое является более конкретным, чемпросто добавьте два числа.Это также позволяет более широко использовать стиль без точек, когда вы объединяете более одной функции.

Также обратите внимание, что с помощью инфиксных функций lke (+) вы можете частично применить их либо к левой, либо к правой стороне, что можетбыть полезным для некоммутативных функций, например

divBy2 :: Float -> Float
divBy2 = (/2)

div2by :: Float -> Float
div2by = (2/)

Prelude> divBy2 3
1.5
Prelude> div2by 2
1.0
0 голосов
/ 27 февраля 2019

Это будет increment x = plus 1 x, но обычно foo x = bar x - это то же самое, что и foo = bar, потому что, если f - это функция, которая возвращает g(x) при вызове с любым аргументом x, тогда fта же функция, что и g.Так что increment = plus 1 работает так же хорошо.

...