Posts mit dem Label funktionale Programmierung werden angezeigt. Alle Posts anzeigen
Posts mit dem Label funktionale Programmierung werden angezeigt. Alle Posts anzeigen

Mittwoch, 6. Juni 2012

Primfaktorzerlegung in Clojure

Habe mal eben schnell (auf Druck einer Person die gerade neben mir sitzt) das Coding Kata der Primfaktorzerlegung in Clojure implementiert. Hier die Lösung:
(defn prime [x] 
  (loop [counter 2
         number x 
         result '()] 
    (if (= 0 (mod number counter)) 
      (recur counter (/ number counter) (conj result counter)) 
      (if (= 1 number) 
        result 
        (recur (inc counter) number result))))) 
Ggf. folgenden noch weitere Lösungen ;-)

Reverse Polish Notation in Clojure - Version 2

Ein weiterer Kollege von mir hat ebenfalls in Clojure eine Lösung für die RPN geschrieben (zu finden hier). Nicht zu verwechseln mit der Scala Lösung von letztem mal (auch hier noch mal der Link ;-)). Ich habe mich auch nochmal dran gesetzt, um weitere Lösungsmöglichkeiten auszuprobieren. Hier ist eine davon. Diese Lösung erstellt eine unendliche Sequnce der einzelen Schritte, in der die RPN aufgelöst wird, dar. Einfach mal selber testen. Denkt bitte daran, die Sequence ist unendlich groß. Also immer nur einen Teil rausholen (zum Beispiel mit range, take oder nth).
(defn calc-next-step [input]
  (if (= 1 (count input)) input
    (loop [[x y] input
           [op & rest-input] (nthnext input 2)
           output ''()]
      (if (number? op)
        (recur [y op] rest-input (concat output (list x)))
        (concat output `(~(op x y)) rest-input )))))

(defn rpn-seq [input]
  (iterate (fn [n] (calc-next-step n)) input))
Der Output kann folgendermaßen aussehen. Ich habe aus Lesbarkeitsgründen die Ausgabe formatiert, und die Clojure-Operatoren durch Zeichen ersetzt, die man dann auch lesen kann ;-). Ansonsten würde der Multiplikator folgendermaßen aussehen:
#<core$_STAR_ clojure.core$_STAR_@3e2f1b1a>

Java toString halt ;-)
Hier die formatierte Ausgabe

(take 5 (rpn-seq (calc-next-step [12 2 3 + 2 * 5 / -])))
((12 5 2 * 5 / -)
(12 10 5 / -)
(12 2 -)
(10)
(10))
Mir ist gerade später aufgefallen, dass der innere Aufruf unnötig ist. Der kann natürlich weggelassen werden ;-). Dann sieht das alles so aus:
(take 5 (rpn-seq [12 2 3 + 2 * 5 / -]))
((12 2 3 + 2 * 5 / -)
(12 5 2 * 5 / -)
(12 10 5 / -)
(12 2 -)
(10))

Reverse Polish Notation in Clojure

Nachdem ein Kollege von mir mal die Reverse Polish Notation (zu deutsch: Umgekehrte Polnische Notation) in Scala implementiert hatte (Link zum Blogeintrag), wollte ich die selbe Aufgabenstellung in Clojure l?sen. Der erste Versuch sah ungefähr so aus:
(ns rpn.core
  (:use [clojure.contrib.string :only (split)]))

(def *operations* {"+" +
                   "-" -
                   "*" *
                   "/" /})

(defn parse-strings [list]
  (map (fn [x] (if (re-find #"^\\d+$" x)
                 (Double/parseDouble x)
                 (*operations* x)))
       list))

(defn rpn [x]
  (let [y (parse-strings (split #"\\s" x))]
    (loop [stack ''()
           rest-of-input y]
      (if (and (= 1 (count stack)) (empty? rest-of-input))
        (first stack)
        (let [next-value (first rest-of-input)]
          (if (number? next-value)
            (recur (conj stack next-value)
                   (rest rest-of-input))
            (recur (conj (nthnext stack 2)
                         (next-value (nth stack 1) (nth stack 0)))
                   (rest rest-of-input))))))))
Da ich länger nichts mehr in Clojure getan hatte, brauchte diese Lösung erstmal seine Zeit und zudem finde ich persönlich diese Lösung irgendwie nicht schön. Aufgrund dessen habe ich mich nochmals dran gesetzt und versucht eine andere Lösung zu finden. Heraus kam das hier:
(ns rpn.core
  (:use [clojure.contrib.string :only (split)]))

(def *operations* {"+" +
                   "-" -
                   "*" *
                   "/" /})

(defn parse-strings [list]
  (map (fn [x] (if (re-find #"^\\d+$" x)
                 (Double/parseDouble x)
                 (*operations* x)))
       list))

(defn rpn [input]
  (reduce (fn [stack op]
            (if (number? op)
              (conj stack op)
              (let [[r l & rest-of-stack] (reverse stack)]
                (conj rest-of-stack (op l r)))))
          []
          (parse-strings (split #"\\s" input))))