开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜