10

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?

Will Ness
  • 70,110
  • 9
  • 98
  • 181
demi
  • 5,384
  • 6
  • 37
  • 57
  • *Pointfree notation :) Pointless notation has a different meaning – daniel gratzer Sep 06 '13 at 02:35
  • 2
    @demi: you should try to edit your question and make it a little more objective, and a little less about "nice" and "good". I find your question interesting (since I know little about Clojure, but I know it lacks read macros, which is the way something like that would be written in Common Lisp, for example), but it is too opinionated. At the moment I'm writing this, there are already 2 votes for closing it, so be warned. – rsenna Sep 06 '13 at 03:01
  • http://dev.clojure.org/jira/browse/CLJ-1760 – Mario Jun 17 '15 at 22:58

4 Answers4

7

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.

tolitius
  • 22,149
  • 6
  • 70
  • 81
  • 3
    The difference isn't so tiny if there are several arguments. Or if their number changes during development. – fjarri Sep 06 '13 at 01:41
  • 2
    this is true. the above is just to illustrate a single argument functions. to "play" with the real (apply .. %&), [here](http://fulldisclojure.blogspot.com/2009/12/how-to-write-clojure-reader-macro-part.html) is a dangerous example of tweaking Clojure [code], whereas [here](https://gist.github.com/liquidz/919875) is a more gentle one [macro]. – tolitius Sep 06 '13 at 01:52
  • @tolitius Oh wow! This link to Disclojure is what I need. I'm very proud that Sean decided to have same syntax I proposed. – demi Sep 06 '13 at 02:56
  • 1
    @demi isn't it a bit of an overkill. If your objective is to have something more concise, why not just define macro, let's say `$` that expands to `partial`? Then you can write `($ + a b ...)` so using the macro nets only 3 characters, just like the one you wanted. – soulcheck Sep 06 '13 at 07:35
5

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)
Leon Grapenthin
  • 9,246
  • 24
  • 37
  • 1
    while it does have a couple of disadvantages (no namespaced "p" and "#p[" is "read stumbling"), it is really cool to demonstrate the usage of `data_readers.clj`. – tolitius Sep 06 '13 at 13:16
  • 1
    It would be great if there were shorthand notations for both partial and comp. E. g. #[] for comp like #[inc second vector] and maybe ~[] for partial, so that one could do #[~[+ 10] ~[* 2]]. My codebase is full of place-stealing partials. – Leon Grapenthin Sep 06 '13 at 14:47
  • 1
    main thing with "enhancing" the reader would be not to get over to the dark side with these `def compose[G[_]](implicit G0: Foldable[G]): Foldable[({type λ[α] = F[G[α]]})#λ]...` :) – tolitius Sep 06 '13 at 15:22
2

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.

demi
  • 5,384
  • 6
  • 37
  • 57
0

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).

D. Ben Knoble
  • 4,273
  • 1
  • 20
  • 38