Concise syntax for partial in Clojure

1.1k views Asked by At

Learning Haskell some time ago, I felt in love with pointfree notation and especially convenient partial function application - just supply args you know. In Clojure, I have partial all the time. I think having a special syntax for partial in reader will be nice to have.

Look at the sample code:

; 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])

This is so nice! Is there something like this? Is there possibility to define custom reader macro?

4

There are 4 answers

4
tolitius On BEST ANSWER

An anonymous function syntax #(...) can be used similarly to what you are trying to do:

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

is equivalent to:

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

A tiny little difference is % which just means a function argument, in this case the first and only.

3
Leon Grapenthin On

I really like your idea for a partial function notation using the #[ ] literal. Unfortunately, Clojure does not let us enhance the #() notation directly, but we can define ourselves a macro like #p for a partial application.

Given you have a function

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

defined in myapp.core. You can add the following entry into the data_readers.clj at the top of your classpath:

{p myapp.core/partial-wrap}

(usually one should use a namespace qualified symbol here like a/p, since unqualified symbols are reserved for Clojure. Nevertheless unqualified symbols do work, you need to rely on Clojure not overwriting them in a future version).

This finally allows to do almost what you asked for:

(map (comp #p[+ 10] #p[* 2]) [1 2 3])
=> (12 14 16)
0
demi On

I found an approach to have partial in cases like in my question: (map #(+ 10 (* 2 %)) [1 2 3). Use ->> macro: (map #(->> % (* 2) (+ 10)) [1 2 3]. Similar macros are ->, .. and doto applicable in different situations.

0
D. Ben Knoble On

If you write code in vim, place the following code in your equivalent of ~/.vim/after/syntax/clojure.vim, and turn conceal on by setting conceallevel to 2:

syntax keyword clojureFunc partial conceal cchar=$

This shortens partial on screen for the reader and writer but doesn’t make a mess of things for others.

I use this trick for making shorthand notations in most languages (e.g., the anonymous function keyword—fn, lambda, whatever—is concealed to the greek letter lambda in many languages).