есть аргументы, которые меняются редко обычно пишутся в начале функции. Например
process :: Param1 -> Param2 -> Arg1 -> Arg2 -> Result
Два первых аргумента функции process выступают в роли параметров для генерации функций с типом
Arg1 -> Arg2 -> Result.
Давайте потренируемся с частичным применением в интерпретаторе. Для этого загрузим модуль Natиз
предыдущей главы:
Prelude> :l Nat
[1 of1] Compiling Nat
( Nat.hs, interpreted )
Ok, modules loaded : Nat.
*Nat> letadd =( +) :: Nat -> Nat -> Nat
*Nat> letaddTwo =add ( Succ( Succ Zero))
*Nat> :t addTwo
addTwo :: Nat -> Nat
*Nat>addTwo ( Succ Zero)
Succ( Succ( Succ Zero))
*Nat>addTwo (addTwo Zero)
Succ( Succ( Succ( Succ Zero)))
Сначала мы ввели локальную переменную add, и присвоили ей метод ( +) из класса Numдля Nat. Нам
пришлось выписать тип функции, поскольку ghci не знает для какого экземпляра мы хотим определить этот
синоним. В данном случае мы подсказали ему, что это Nat. Затем с помощью частичного применения мы
объявили новый синоним addTwo, как мы видим из следующей строки это функция оного аргумента. Она
принимает любое значение типа Natи прибавляет к нему двойку. Мы видим, что этой функцией можно
пользоваться также как и обычной функцией.
Попробуем выполнить тоже самое для функции с символьной записью имени:
*Nat> letadd2 =( +) ( Succ( Succ Zero))
*Nat>add2 Zero
Succ( Succ Zero)
Мы рассмотрели частичное применение для функций в префиксной форме записи. В префиксной фор-
ме записи функция пишется первой, затем следуют аргументы. Для функций в инфиксной форме записи
существует два правила применения.
Это применение слева:
( *) ::a ->(b ->c),
x ::a
-----------------------------
(x *) ::b ->c
И применение справа:
( *) ::a ->(b ->c),
x ::b
-----------------------------
( *x) ::a ->c
Обратите внимание на типы аргумента и возвращаемого значения. Скобки в выражениях (x *) и ( *x)
обязательны. Применением слева мы фиксируем в бинарной операции первый аргумент, а применением
справа – второй.
Поясним на примере, для этого давайте возьмём функцию минус ( -). Если мы напишем (2 -) 1 то мы
получим 1, а если мы напишем ( -2) 1, то мы получим -1. Проверим в интерпретаторе:
*Nat>(2 -) 1
1
*Nat>( -2) 1
<interactive >:4 :2 :
Структура функций | 47
No instancefor ( Num(a0 ->t0))
arising from a use ofsyntactic negation
Possiblefix :add an instancedeclaration for ( Num(a0 ->t0))
Inthe expression : -2
Inthe expression :( -2) 1
Inan equation for ‘it’ :it =( -2) 1
Ох уж этот минус. Незадача. Ошибка произошла из-за того, что минус является хамелеоном. Если мы
пишем -2, компилятор воспринимает минус как унарную операцию, и думает, что мы написали константу
минус два. Это сделано для удобства, но иногда это мешает. Это единственное такое исключение в Haskell.
Давайте введём новый синоним для операции минус:
*Nat> let( #) =( -)
*Nat>(2 #) 1
1
*Nat>( #2) 1
-1
Эти правила левого и правого применения работают и для буквенных имён в инфиксной форме записи:
*Nat> letminus =( -)
*Nat>(2 ‘minus‘ ) 1
1
*Nat>( ‘minus‘ 2) 1
-1
Так если мы хотим на лету получить новую функцию, связав в функции второй аргумент мы можем
написать:
... = ...( ‘fun‘ x) ...
Частичное применение для функций в инфиксной форме записи называют сечением (section), они бывают
соответственно левыми и правыми.
Связь с логикой
Отметим связь основного правила применения с Modus Ponens, известным правилом вывода в логике:
a ->b,
a
-------------
b
Оно говорит о том, что если у нас есть выражение из a следует b и мы знаем, что a истинно, мы смело
можем утверждать, что b тоже истинно. Если перевести это правило на Haskell, то мы получим: Если у нас
Читать дальше