Can you translate these 2 examples from Functional Languages 101 ? (Scheme -> Clojure)
Got these examples I would like to understand but they are in Scheme. I would like them in Clojure :D
Example 1 - counting the length of a list
(define length
(lambda (ll)
(cond
((null? ll) 0)
(#t (add1
(length (cdr ll)))))))
Exemple 2 - square each element of a list
(define squares
(lambda (li)
(cond
((null? li) ())
(#t (cons
(* (char li) (char li))
(squares(cdr
li)))))))
Example 3 - the "map" function (as in map/reduce)
(define map (lambda (func lst)
(cond ((null? lst) ())
(#t (cons (func (car lst))
(map func (cdr lst)))))))
Curried "map"
(define map2
(lambda (func)
(lambda (lst)开发者_开发问答
(cond ((null? lst) ())
(#t (cons (func (car lst))
((map2 func) (cdr lst)))))))
Motivation
The examples are from a presentation on Functional Programming someone else might be interested it: Functional Languages 101: What’s All the Fuss About?
Once you submit an answer, I'd like your agreement to post it as a comment at that presentation for Clojure people to understand the original code
I have some stoff here: http://github.com/nickik/Essentials-of-PLs-in-Clojure/blob/master/src/EssentialsOfProgrammingLanguages/core.clj
Its all scheme to clojure stuff. You can download the source of the Essentials of Programming Languages-Book to have the Scheme code.
Here are your examples:
(defn length [lst]
(cond
(seq ll) 0
:else (inc (length (rest lst))))))
Note: clojure has a count function
(defn squares1 [li]
(cond (nil? (seq li)) (empty li)
:else (conj (squares1 (rest li)) (* (first li) (first li)))))
(defn squares2 [li]
(map #(* % %) li))
(defn mymap [f coll]
(cond (nil? (seq coll)) (empty coll)
:else (conj (mymap f (rest coll)) (f (first coll)))))
(defn map2 [f]
(fn [lst]
(cond (nil? (seq lst)) (empty lst)
:else (conj ((map2 f) (rest lst)) (f (first lst))))))
Note you can not just make a 1:1 translation. The diffrence between how '() evals and so on.
Here are the most importend ones
- (nil? (seq list)) not (null? lst) because '() is not nil in clojure
- conj is better then cons you can make the function work with mure datastructures
- (empty lst) is better then '() because (empty lst) keeps the type vector, list, record, structs or something else
Length of a list:
(defn my-length [lst]
(loop [len 0 x lst]
(if (empty? x)
len
(recur (+ 1 len) (rest x)))))
user=> (my-length '(1))
1
user=> (my-length '(1 2 3 4))
4
user=> (my-length '())
0
Square each element of a list:
(defn squares [lst]
(loop [sqrs '() x lst]
(if (empty? x)
(reverse sqrs)
(recur (cons (* (first x) (first x)) sqrs) (rest x)))))
user=> (squares '(1 2 3 4))
(1 4 9 16)
Map:
(defn my-map [func lst]
(loop [res '() x lst]
(if (empty? x)
(reverse res)
(recur (cons (func (first x)) res) (rest x)))))
user=> (my-map (fn [x] (* x 2)) '(1 2 3))
(2 4 6)
Map2:
See nickik's solution.
And more clojurey translation of map
:
(defn map
[f coll]
(lazy-seq
(when-let [s (seq coll)]
(cons (f (first s)) (map f (rest s))))))
Exploit closures: define map-inner
like map
above.
(defn map
[f]
(fn [coll]
(map-inner f coll)))
In idiomatic clojure normally you exploit that the nil is logical false.
(defn length
[coll]
(loop [s (seq coll)
len 0]
(if s
(recur (next s) (inc len))
len)))
As with map
: you would use lazy sequences instead of eager lists.
(defn squares
[coll]
(lazy-seq
(when-let [s (seq coll)]
(let [fst (first s)]
(cons (* fst fst) (squares (rest s)))))))
define
is def
in clojure, lambda
is fn
, function arguments are written as vectors []
, not lists ()
, null?
is empty
, car
is first
, cdr
is rest
and the default case for cond
is specified with :else
, not #t
.
So for your first example we get:
(def length
(fn [ll]
(cond
(empty? ll) 0
:else (+ 1 (length (rest ll))))))
This can be written a little more succinctly using defn
instead of def
and fn
, but the same is true for the scheme version, so I chose the way that is the closest to the original.
The other examples can be translated the same way.
精彩评论