Является ли раздел результатом каррирования?

В программировании на Haskell от Хаттона

In general, if # is an operator, then expressions of the form (#), (x #), and (# y) for arguments x and y are called sections, whose meaning as functions can be formalised using lambda expressions as follows:

(#)   =   \x  ->  (\y ->  x   #   y)
(x    #)  =   \y  ->  x   #   y
(#    y)  =   \x  ->  x   #   y

В чем разница и связь между «разделом» и «каррингом»?

Является ли раздел результатом применения операции каррирования к функции с несколькими аргументами?

Спасибо.

Раздел — это именно то, о чем говорится в цитируемом абзаце. Какое это имеет отношение к карри?

melpomene 13.07.2019 14:53

Представьте себе язык с функциями в инфиксной записи. Бинарная функция могла бы выглядеть так (2)sub(3) — да, мне тоже глаза режет. Левая/правая часть будет (2)sub/sub(3). Очевидно, что это не работает с функциями с несколькими аргументами. Единственная связь между каррированием и секциями, которую можно увидеть, заключается в том, что вам нужны каррированные функции для выражения с ними секций операторов.

Iven Marquardt 13.07.2019 15:47

В том смысле, что секции допускают частичное применение инфиксного оператора, аналогичного префиксной нотации, да.

chepner 13.07.2019 16:30
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
154
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Раздел — это просто специальный синтаксис для применения инфиксного оператора к одному аргументу. (# y) является более полезным из двух, поскольку (x #) эквивалентен (#) x (который просто применяет инфиксный оператор как функцию к одному аргументу обычным способом).

(#) это тоже раздел.
melpomene 13.07.2019 15:46

@melpomene Строго говоря, я так не думаю. Раздел 3.5 отчета говорит только о левых и правых разделах; синтаксис (#) упоминается отдельно в раздел 3.2.

duplode 13.07.2019 15:50

Хм. Вы совершенно правы, но в книге Хаттона дается другое определение. И я смутно помню, что видел это где-то еще, только не могу вспомнить где.

melpomene 13.07.2019 15:56

@melpomene Вы напомнили мне об этом: раздел 4.2 История Haskell: лень с классом действительно относится к (#) как к разделу, а объединяющая тема заключается в том, чтобы сделать инфиксные операторы первоклассными. Можно сказать, что независимо от того, как в Отчете названы вещи, не случайно синтаксис в обоих случаях почти одинаков.

duplode 13.07.2019 16:22

Однажды я спросил откуда пошло слово "секция", и там не было ясного источника. Меня не удивит отсутствие строгого определения; интуитивно я думаю об этом как о частичном применении инфиксных операторов, где (#) выглядит как разделы, но не обязательно связано с ними. Можно возразить, что оператор, «примененный» к нулевым аргументам, оценивает «основную» функцию.

chepner 13.07.2019 16:29

Спасибо. В чем разница и связь между «разделом» и «каррингом»? Является ли раздел результатом применения операции каррирования к функции с несколькими аргументами?

Tim 13.07.2019 16:30

Что-то вроде. Инфиксный оператор — это просто синтаксическая тонкость; она каррирована, как и любая другая функция, но вы пишете ее приложение в другой форме. Чтобы перетащить сюда обратные кавычки (где plus 3 5 и 3 `plus` 5 эквивалентны), разделы позволяют писать (3 +) так же, как вы можете писать plus 3. Вы также можете написать (+ 5) там, где нет прямого эквивалента, используя префиксную нотацию, не используя flip. (+ 5) то же, что flip plus 5.

chepner 13.07.2019 16:33

@Tim Почему ты разместил этот комментарий? Это просто повторение вашего вопроса.

melpomene 13.07.2019 18:37
Ответ принят как подходящий

Левая и правая части — это синтаксические устройства для частичного применения инфиксного оператора к одному аргументу (см. также ответ Чепнера). Ради точности отметим, что каррирование — это не то же самое, что частичное применение:

  • Каррирование — это преобразование функции, которая принимает аргументы Н, в функцию, которая принимает один аргумент и возвращает функцию, которая принимает аргументы Н-1.

  • Частичное приложение создает функцию, которая принимает аргументы Н-1, из функции, которая принимает аргументы Н, предоставляя один из аргументов.

В Haskell бывает, что все каррировано; все функции принимают только один аргумент (даже некаррированные функции в Haskell принимают кортеж, который, строго говоря, является одним аргументом — вы можете поиграть с функциями curry и uncurry, чтобы увидеть, как это работает). Тем не менее, мы очень часто неформально думаем о функциях, возвращающих функции, как о функциях с несколькими аргументами. С этой точки зрения хорошим следствием каррирования по умолчанию является то, что частичное применение функции к ее первому аргументу становится тривиальным: в то время как, например, elem принимает значение и контейнер и проверяет, является ли значение элементом контейнера, elem "apple" берет контейнер (строк) и проверяет, является ли "apple" его элементом.

Что касается операторов, когда мы пишем, например...

5 / 2

... мы применяем оператор / к аргументам 5 и 2. Оператор также может использоваться в префиксной форме, а не в инфиксной:

(/) 5 2

В префиксной форме оператор может частично применяться обычным образом:

(/) 5

Это, однако, возможно, выглядит немного неловко — в конце концов, 5 здесь числитель, а не знаменатель. Я бы сказал, что в этом случае синтаксис левой секции проще для глаз:

(5 /)

Кроме того, частичное применение ко второму аргументу не так просто написать, требующее лямбда или flip. В случае с операторами в этом может помочь правая секция:

(/ 2)

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

(`elem` ["apple", "grape", "orange"])

... берет строку и проверяет, можно ли ее найти в ["apple", "grape", "orange"].

curry f x y = f (x,y). uncurry g (x,y) = g x y.

(+ 3) 4 = (+) 4 3 = 4 + 3. (4 +) 3 = (+) 4 3 = 4 + 3.

Раздел является результатом частичное применение функции карри: (+ 3) = flip (+) 3, (4 +) = (+) 4.

Каррированная функция (например, g или (+)) ожидает свои аргументы по одному. Функция без карри (например, f) ожидает свои аргументы в кортеже.

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

curry   :: ((a, b)  -> c ) -> ( a -> (b -> c))
uncurry :: (a -> (b -> c)) -> ((a, b)   -> c )

 x :: a
 g :: a -> (b -> c)       
--------------------
 g    x ::  b -> c  

 x       ::  a
 f       :: (a, b)   -> c
---------------------------
 curry f ::  a -> (b -> c)
 curry f     x ::  b -> c

Другие вопросы по теме