Краткий синтаксис для частичного в Clojure

Некоторое время назад, изучая Haskell, я влюбился в бесточечную нотацию и в особенно удобное приложение с частичными функциями — знаете, просто укажите аргументы. В Clojure у меня все время partial. Я думаю, что было бы неплохо иметь специальный синтаксис для частичного в читателе.

Посмотрите на пример кода:

; Notation with points:
(map (+ 10 (* % 2)) [1 2 3])

; With partial:
(map (comp (partial + 10) (partial * 2)) [1 2 3])

; Let #[] syntax means partial application in reader:
(map (comp #[+ 10] #[* 2]) [1 2 3])

Это так приятно! Есть ли что-то подобное? Есть ли возможность определить пользовательский макрос для чтения?


person demi    schedule 06.09.2013    source источник
comment
*Бесточечная нотация :) Бесточечная нотация имеет другое значение   -  person Daniel Gratzer    schedule 06.09.2013
comment
@demi: вы должны попытаться отредактировать свой вопрос и сделать его немного более объективным и немного менее приятным и хорошим. Я нахожу ваш вопрос интересным (поскольку я мало знаю о Clojure, но я знаю, что ему не хватает макросов чтения, как, например, что-то подобное было бы написано на Common Lisp), но он слишком самоуверен. На данный момент, когда я это пишу, уже есть 2 голоса за его закрытие, так что будьте осторожны.   -  person rsenna    schedule 06.09.2013
comment
dev.clojure.org/jira/browse/CLJ-1760   -  person Mario    schedule 18.06.2015


Ответы (4)


Синтаксис анонимной функции #(...) можно использовать аналогично тому, что вы пытаетесь сделать:

user=> (map (comp (partial + 10) (partial * 2)) [1 2 3])
(12 14 16) 

эквивалентно:

user=> (map (comp #(+ 10 %) #(* 2 %)) [1 2 3])
(12 14 16)

Небольшое отличие состоит в том, что % означает просто аргумент функции, в данном случае первый и единственный.

person tolitius    schedule 06.09.2013
comment
Разница не так мала, если аргументов несколько. Или если их количество меняется в процессе разработки. - person fjarri; 06.09.2013
comment
это правда. приведенное выше просто иллюстрирует функции одного аргумента. играть с настоящим (применить .. %&), здесь — опасный пример подстройки [кода] Clojure, тогда как здесь более щадящий [макрос]. - person tolitius; 06.09.2013
comment
@tolitius Ого! Эта ссылка на Disclojure — то, что мне нужно. Я очень горжусь тем, что Шон решил использовать тот же синтаксис, что и я. - person demi; 06.09.2013
comment
@demi, разве это не перебор? Если ваша цель — сделать что-то более лаконичное, почему бы просто не определить макрос, скажем, $, который расширяется до partial? Затем вы можете написать ($ + a b ...), чтобы с помощью макроса получилось только 3 символа, как и тот, который вы хотели. - person soulcheck; 06.09.2013

Мне очень нравится ваша идея для обозначения частичной функции с использованием литерала #[ ]. К сожалению, Clojure не позволяет нам напрямую улучшать нотацию #(), но мы можем сами определить макрос, например #p, для частичного приложения.

Учитывая, что у вас есть функция

(defn partial-wrap
  [args]
  (concat '(partial) args))

определено в myapp.core. Вы можете добавить следующую запись в data_readers.clj вверху пути к классам:

{p myapp.core/partial-wrap}

(обычно здесь следует использовать квалифицированный символ пространства имен, например a/p, поскольку неквалифицированные символы зарезервированы для Clojure. Тем не менее, неквалифицированные символы работают, вам нужно полагаться на то, что Clojure не перезапишет их в будущей версии).

Это, наконец, позволяет делать почти то, что вы просили:

(map (comp #p[+ 10] #p[* 2]) [1 2 3])
=> (12 14 16)
person Leon Grapenthin    schedule 06.09.2013
comment
хотя у него есть несколько недостатков (нет пространства имен p и #p[ читается спотыкаясь), действительно здорово продемонстрировать использование data_readers.clj. - person tolitius; 06.09.2013
comment
Было бы здорово, если бы были сокращенные обозначения как для парциального, так и для комп. напр. #[] для comp как #[inc second vector] и, возможно, ~[] для partial, чтобы можно было сделать #[~[+ 10] ~[* 2]]. Моя кодовая база полна фрагментов, занимающих много места. - person Leon Grapenthin; 06.09.2013
comment
главное с усилением читалки не перейти на темную сторону с этими def compose[G[_]](implicit G0: Foldable[G]): Foldable[({type λ[α] = F[G[α]]})#λ]... :) - person tolitius; 06.09.2013

Я нашел подход к частичному в таких случаях, как в моем вопросе: (map #(+ 10 (* 2 %)) [1 2 3). Используйте макрос ->>: (map #(->> % (* 2) (+ 10)) [1 2 3]. Подобные макросы ->, .. и doto применимы в разных ситуациях.

person demi    schedule 11.09.2013

Если вы пишете код в vim, поместите следующий код в эквивалент ~/.vim/after/syntax/clojure.vim и включите скрытие, установив conceallevel в 2:

syntax keyword clojureFunc partial conceal cchar=$

Это сокращает partial на экране для читателя и писателя, но не создает беспорядка для других.

Я использую этот трюк для создания сокращенных обозначений в большинстве языков (например, ключевое слово анонимной функции — fn, lambda, что угодно — во многих языках скрыто за греческой буквой lambda).

person D. Ben Knoble    schedule 23.01.2020