Skip to content

Instantly share code, notes, and snippets.

@roman
Created November 27, 2011 18:56
Show Gist options
  • Save roman/1397984 to your computer and use it in GitHub Desktop.
Save roman/1397984 to your computer and use it in GitHub Desktop.
Keep the important parameter first!
(ns main
(:require [clojure.string :as string]))
; this code is to solve the following algorithmic problem:
; http://www.spoj.pl/problems/ADDREV/
(def sum (partial reduce + 0))
(defn main [& args]
(let [n (Integer/parseInt (read-line))]
(repeatedly n reverse-sum)))
(defn flip [g] (fn [a b] (g b a)))
(defn reverse-sum []
(let [rmap (flip map)]
(-> (read-line)
(string/split #"\s+")
(rmap string/reverse)
(rmap #(Integer/parseInt %))
sum
str
string/reverse
(string/replace #"^0+" "")
(rmap println))))
@roman
Copy link
Author

roman commented Nov 27, 2011

@Nakort, in clojure it seems there is two kinds of functions (I say it seems, because I'm not 100% familiar with all clojure's core apis), the ones that receive the important parameter first, and the ones that receive the important parameter last.

clojure.string functions receive important parameter first, meaning, the string you are going to be working with is received first, some examples:

(string/split "string-to-work-with" #"match-to-split")
(string/replace "string-to-work-with" #"match-to-replace" "replacement")

the collection functions receive parameters last:

(map mapping-fn coll)
(reduce + 0 coll-of-numbers)
;... 

There are two functions to compose functions together -> and ->>, with -> you compose functions like the one in clojure.string module, with ->> you compose functions like the ones in collections. I didn't see why they do this, given that if you follow a standard (important parameter first or important parameter last) all functions may be composable, and you would use just one -> or->>.

It seems you don't want to be able to compose some functions with others:

From clojure.string docs

Strings are objects (as opposed to sequences). As such, the
string being manipulated is the first argument to a function.

Tweet from @swannodette (Main developer of core.logic, making him an authority IMO)

@romanandreg the string operations are strict - even disregarding arg order, not ideal
to compose w/ map/filter/reduce/etc

I found that quite frustrating and limiting, I imagine, given that clojure doesn't have a type system you can shoot yourself in the foot pretty easily; however there are cases where functions in the clojure.string module return collections (split for example), and I would like to be able to compose them. I found a way by implementing the basic flip function (line #13) which is not really difficult, this might not work in other scenarios though.

Just observations and opinions, that's all.

@swannodette
Copy link

It's a minor annoyance. clojure.string does not treat Java strings as sequences for a practical reason - performance. So you're going to run into problems with the threading operators as you move between sequences and strings.

@roman
Copy link
Author

roman commented Nov 27, 2011

Interesting, I was wondering why there wasn't a drop-while, take-while functions with Strings in Clojure (Whenever I tried to used them with Strings I got back a coll of characters rather than another String). It makes sense now given what you said that performance is the main issue.

The problem with minor annoyances is that they add up little by little. Hopefully this list of small annoyances won't grow to much while I'm getting deeper into the rabbit hole of Clojure :-).

Thanks for your feedback @swannodette.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment