Friday, 10 March 2017

How to style your input file in Reagent with Bootstrap

Ok this caused me a lot of headache, hope it will help anyone.
In bootstrap the only way to style a input with type file, is to close it in a label. Like this:
  • <label class="btn btn-default btn-file"> Browse <input type="file" style="display: none;"> </label>
   

Unfortunately, as things are now, the only way to do something like this in Reagent is to set the InnerHhtml and do something like this:

(defn ^:export on-click
  [event]
  (js/alert "Upload Button Clicked")

(defn ^:export on-change
  [event]
  (js/alert "File Changed)

(def input-html "<input id='upload-file' name='updload-file' type='file' 
style='display: none;' onclick='{ns}.table.on_click(event)' 
onchange='{ns}.table.on_change(event);'></input>")

[:label.btn.btn-primary.col-span-1
     {:dangerouslySetInnerHTML
      {:__html (str (label-input "Select File") input-html)}}]


Also the javascript functions that will be called will have to be exported and called using {ns}.function
This is the only 'non elegant' solution that is possible now.
An interesting thing that give me headache was this one.
I wanted to change the label str ("Select File") in the on-change function. I used a reagent atom for that and changed the label in this way:

(def label (reagent/atom "Select File"))

(defn ^:export on-change
  [event]
  (reset! label "New Label)
[:label.btn.btn-primary.col-span-1      {:dangerouslySetInnerHTML       {:__html (str (label-input @label) input-html)}}]
This actually cause the input to loose it's file because React replace the <label> with it's html recreating the input and loosing the file.
Hope this will prevent some other guys to have the same headache I had :D

Thursday, 9 March 2017

How to do an upload using REST (Swagger) and Clojurescript (ajav

Hoping to help someone else that is also struggling with this.
I have used Luminus with Reagent to try this.
Luminus come with Swagger for REST API, it's a great tool because it gives you the possibility to try the API as soon as you have write it.
This is the code to write a REST end-point that accept a file in upload

(ns your-clojure-ns
  (:require [ring.util.http-response :refer :all]
            [compojure.api.sweet :refer :all]
            [schema.core :as s]
            [ring.swagger.upload :as upload])

(defapi service-routes
  {:swagger {:ui "/swagger-ui"
             :spec "/swagger.json"
             :data {:info {:version "1.0.0"
                           :title "Sample API"
                           :description "Sample Services"}}}}

  (context "/your-context" []
    :tags ["Your Context"]

    (POST "/upload" []
      :multipart-params [file :- upload/TempFileUpload]
      :middleware       [upload/wrap-multipart-params]
      (ok (let [{:keys [filename tempfile]} file ]
            (do-something-with tempfile)
            {:success true}))))



You should already have the right imports in the file created by Luminus, the only one that you have to add is [ring.swagger.upload :as upload] that will give you the Middleware to use for your request.
Once you have added this. You should see in your Swagger ui (localhost:3000/swagger-ui) your new API, with the possibility to already send a file to try your logic (do-something-with)
Now let's go to the Clojurescript call (that is the hardest part, I lost an evening to figure out the right combination)

(ns your-clojurescript-ns
  (:require [ajax.core :refer [GET POST]]))

(defn upload-file [file]
  (letfn [(handle-response-ok [] (js/alert "File Uploaded")
          (handle-response-error [] (js/alert "There were problems during the upload"))]
    (let [form-data (doto
                      (js/FormData.)
                      (.append "file" file))]
      (POST "/your-context/upload"
            {:body form-data
             :response-format :json
             :keywords? true
             :handler handle-response-ok
             :error-handler handle-response-error}))))



(.append "file" file) is very important, file is the same name you used in the clojure namespace as parameter, also you have to send the form-data as :body, if you try to send it as a :params (like is written around in internet) you will have an error.
Hope this post will be useful.

Coming soon... How to style your input with a file using Bootstrap, Reagent and Clojurescript. How changing the label using a Reagent atom can give you some headache.

First project with Luminus and Reagent... impressions.

Ok I have started a project for a friend https://github.com/marcomanzi/arcatron, it's web application to charge customers for calls done.
I'm using Luminus with Reagent as frontend... how it is going...
I will compare this with my experience in doing something similar using Java, with Spring and Vaadin. During this development I had more feeling coming out, these are the things I want to share (not ordered by relevance)

  • Fun: Well, this is a totally new experience, I have Terminator with 3 windows, one with lein test-refreh, one with lein run and one with lein figwheel. I really enjoy that I see happening in my browser while I change them. It's a new experience because with Vaadin every little change I had to restart the application server (it does not take long though)
  • Creativity: Because there is not a clear path written (with Spring a Vaadin you are taken by hand and they guide you to the final result like a parent with a child) I was able to come out with my solutions for problems, like the creation of a paginated-table that handle the rendering of a table that automatically resize when the browser window change size.
  • Frustration: well also this feeling come out a lot... I'm using swagger to create Rest API, and I'm calling them using ajax.core Get and POST methods. Using a dynamic language is very hard because if you can't find documentation on Internet you are not able to figure how you should use these functions. For example it took me a good evening to make the upload of a file working because I was using the :params key in the POST configuration map instead of the :body, and there was really no feedback to understand that
  • Productivity is still very low: Unfortunately the horrible stacktrace of clojure and the error messages make me think that there is still work to do in that direction in clojure to make it more productive.
Next steps:
  • Improve my paginated table to make it easier to use, I was not able to encapsulate it fully.
  • Move to clojure 1.9 to check if errors are a little more useful
Wishes:
  • Luminus is a good framework, but still documentation is poor on simple tasks (like doing a full rest application with clojurescript as frontend, lots of common problems (like timeout or security using tokens, ..) don't have a documented solution leaving open the implementation. These are problems that are "old", production tested solution should be documented in the framework and should take less time to set it up.
If any of you want to go through the code and give me some advice I will gratefully accept that, I feel that I still have to learn a lot on how to write functional programming but I only have my free time to try it :), help from someone is great, also if you have a project where you need some help, let me know.




Monday, 16 January 2017

SICP in Clojure: Chapter 2 (part 1)

Going on with my study of SICP, this is the first part of chapter 2 (that is a very big chapter and also has a lot of great examples). I also updated the code in the first chapter for some issues with chapter 2 names that were replicated (I made some private definitions there to use refer all here).
The painter example of this book was really cool and actually you can create a painter with Quil library if you want to see it works.

(ns sicp.chapter-2
  (:require [sicp.chapter-1 :refer :all]))

;Common functions
(defn null? [l] (and (seq? l) (empty? l)))
;Chapther 2: Building Abstractions with Data
(defn linear-combination [a b x y]
  (+ (* a x) (* b y)))
(declare add mul)
(defn linear-combination [a b x y]
  (add (mul a x) (mul b y)))

;Chapter 2.1.1
(declare make-rat numer denom)
(defn add-rat [x y]
  (make-rat (+ (* (numer x) (denom y))
               (* (numer y) (denom x)))
            (* (denom x) (denom y))))
(defn sub-rat [x y]
  (make-rat (- (* (numer x) (denom y))
               (* (numer y) (denom x)))
            (* (denom x) (denom y))))
(defn mul-rat [x y]
  (make-rat (* (numer x) (numer y))
            (* (denom x) (denom y))))
(defn div-rat [x y]
  (make-rat (* (numer x) (denom y))
            (* (denom x) (numer y))))
(defn equal-rat? [x y]
  (= (* (numer x) (denom y))
     (* (numer y) (denom x))))
(def x (cons 1 [2]))
(first x)
(second x)
(def x (cons 1 [2]))
(def y (cons 3 [4]))
(def z (cons x (cons y [])))
(first (first z))
(first (second z))
(defn make-rat [x y] (cons x [y]))
(def numer first)
(def denom second)
(defn print-rat [x]
  (println "")
  (println (str (numer x) "/" (denom x))))
(def one-half (make-rat 1 2))
(print-rat one-half)
(def one-third (make-rat 1 3))
(print-rat (add-rat one-half one-third))
(print-rat (mul-rat one-half one-third))
(print-rat (add-rat one-third one-third))
(defn make-rat [n d]
  (let [g (gcd n d)]
    (cons (/ n g) [(/ d g)])))

(print-rat (add-rat one-third one-third))
(defn make-rat [n d]
  (cons n [d]))
(defn numer [x]
  (let [g (gcd (first x) (second x))]
    (/ (first x) g)))
(defn denom [x]
  (let [g (gcd (first x) (second x))]
    (/ (second x) g)))
(print-rat (add-rat one-third one-third))
(defn cons [x y]
  (letfn [(dispatch [m]
            (cond (= m 0) x
                  (= m 1) y
                  :else (println "Argument not 0 or 1: CONS" m)))]
    dispatch))
(defn car [z] (z 0))
(defn cdr [z] (z 1))

;Exercise 2.4
(defn cons [x y]
  #(% x y))
(defn car [z]
  (z (fn [p q] p)))

(defn cdr [z]
  (z (fn [p q] q)))

;Exercise 2.6
(def zero (fn [f] (fn [x] x)))
(defn add-1 [n]
  (fn [f] (fn [x] (f (n f) x))))

;Chapters 2.1.4
(declare make-interval lower-bound upper-bound)
(defn add-interval [x y]
  (make-interval (+ (lower-bound x) (lower-bound y))
                 (+ (upper-bound x) (upper-bound y))))
(defn mul-interval [x y]
  (let [p1 (* (lower-bound x) (lower-bound y))
        p2 (* (lower-bound x) (upper-bound y))
        p3 (* (upper-bound x) (lower-bound y))
        p4 (* (upper-bound x) (upper-bound y))]
    (make-interval (min p1 p2 p3 p4)
                   (max p1 p2 p3 p4))))
(defn div-interval [x y]
  (mul-interval
   x
   (make-interval (/ 1.0 (upper-bound y))
                  (/ 1.0 (lower-bound y)))))

;Exercise 2.7
(defn make-interval [a b]
  (cons a [b]))
(defn upper-bound [x] (first x))
(defn lower-bound [x] (second x))

;Exercise 2.11
(defn make-center-width [c w]
  (make-interval (- c w) (+ c w)))
(defn center [i]
  (/ (+ (lower-bound i) (upper-bound i)) 2))
(defn width [i]
  (/ (- (upper-bound i) (lower-bound i)) 2))

;Exercise 2.13
(defn par1 [r1 r2]
  (div-interval (mul-interval r1 r2)
                (add-interval r1 r2)))
(defn par2 [r1 r2]
  (let [one (make-interval 1 1)]
    (div-interval
     one (add-interval (div-interval one r1)
                       (div-interval one r2)))))

;Chapter 2.2.1
(def cons clojure.core/cons)
(cons 1
      (cons 2
            (cons 3
                  (cons 4 nil))))
(list 1 2 3 4)
(def one-through-four (list 1 2 3 4))
(first one-through-four) ;first instead of car
(rest one-through-four)  ;rest instead of car
(first (rest one-through-four))
(cons 10 one-through-four)
(cons 5 one-through-four)

;List Operations
(defn list-ref [items n]
  (if (= n 0)
    (first items)
    (list-ref (rest items) (- n 1))))
(def squares (list 1 4 9 16 25))
(list-ref squares 3)
(defn length [items]
  (if (empty? items)
    0
    (+ 1 (length (rest items)))))
(def odds (list 1 3 5 7))
(length odds)
(defn length [items]
  (letfn [(length-iter [a count]
            (if (empty? a)
              count
              (length-iter (rest a) (+ 1 count))))]
    (length-iter items 0)))
(defn append [list1 list2]
  (if (empty? list1)
    list2
    (cons (first list1) (append (rest list1) list2))))
(append squares odds)
(append odds squares)

;Exercise 2.19
(def us-coins (list 50 25 10 5 1))
(def uk-coins (list 100 50 20 10 5 2 1 0.5))
(declare no-more? except-first-denomination)
(defn cc2-19 [amount coin-values]
  (cond (= amount 0) 1
        (or (< amount 0) (no-more? coin-values)) 0
        :else
        (+ (cc amount
               (except-first-denomination coin-values))
           (cc (- amount
                  (first-denomination coin-values))
               coin-values))))

;Exercise 2.20
(comment  (defn fn-name [ & <parameters>] <body>)
          (def f (fn [x y & z] <body>))
          (def g (fn [& w] <body>)))

;Mapping over a list
(defn scale-list [items factor]
  (if (empty? items)
    nil
    (cons (* (first items) factor)
          (scale-list (rest items) factor))))
(scale-list (list 1 2 3 4 5) 10)

(defn map-ex [proc items]
  (if (empty? items)
    nil
    (cons (proc (first items))
          (map-ex proc (rest items)))))
(map-ex abs (list -10 2.5 -11.6 17))
(map #(* % %) (list 1 2 3 4))
(defn scale-list [items factor]
  (map #(* % factor) items))
;Exercise 2.21
(declare <??>)
(defn square-list [items]
  (if (empty? items)
    nil
    (cons <??> <??>)))
(defn square-list [items]
  (map <??> <??>))

;Exercise 2.22
(defn square-list [items]
  (letfn [(iter [things answer]
            (if (empty? things)
              answer
              (iter (rest things)
                    (concat (square (rest things))
                            answer))))]
    (iter items nil)))
(defn square-list [items]
  (letfn [(iter [things answer]
            (if (empty? things)
              answer
              (iter (rest things)
                    (cons answer
                          (concat (rest things))))))]
    (iter items nil)))

;Exercise 2.23
(def for-each map)
(for-each (fn [x]
            (println "")
            (println x))
          (list 57 321 88))

;Chapter 2.2.2
(defn count-leaves [x]
  (cond (and (seq? x) (empty? x)) 0
        ((complement seq?) x) 1
        :else (+ (count-leaves (first x))
                 (count-leaves (rest x)))))
(cons (list 1 2) (list 3 4))
(def x (cons (list 1 2) (list 3 4)))
(length x)
(count-leaves x)
(list x x)
(length (list x x))
(count-leaves (list x x))

;Exercise 2.26
(def x (list 1 2 3))
(def y (list 4 5 6))
(append x y)
(cons x y)
(list x y)

;Exercise 2.27
(def x (list (list 1 2) (list 3 4)))
x
(reverse x)
(comment  (deep-reverse x))

;Exercise 2.29
(defn make-mobile [left right]
  (list left right))
(defn make-branch [length structure]
  (list length structure))

;Mapping over trees
(defn scale-tree [tree factor]
  (cond (null? tree) nil
        ((complement seq?) tree) (* tree factor)
        :else (cons (scale-tree (first tree) factor)
                    (scale-tree (rest tree)  factor))))
(scale-tree (list 1 (list 2 (list 3 4) 5) (list 6 7)) 10)
(defn scale-tree [tree factor]
  (map (fn [sub-tree]
         (if (seq? sub-tree)
           (scale-tree sub-tree factor)
           (* sub-tree factor)))
       tree))

;Exercise 2.31
(declare tree-map)
(defn square-tree [tree] (tree-map square tree))

;Exercise 2.32
(defn subsets [s]
  (if (null? s)
    (list nil)
    (let [rest (subsets (rest s))]
      (concat rest (map <??> rest)))))

;Chapter 2.2.3
(defn sum-odd-squares [tree]
  (cond (null? tree) 0
        (not (seq? tree)) (if (odd? tree)
                            (square tree)
                            0)
        :else (+ (sum-odd-squares (first tree))
                 (sum-odd-squares (rest tree)))))
(defn even-fibs [n]
  (letfn [(next [k]
            (if (> k n)
              nil
              (let [f (fib k)]
                (if (even? f)
                  (cons f (next (+ k 1)))
                  (next (+ k 1))))))]
    (next 0)))

;Sequence Operations
(map square (list 1 2 3 4 5))
(defn filter [predicate sequence]
  (cond (null? sequence) nil
        (predicate (first sequence)) (cons (first sequence)
                                           (filter predicate (rest sequence)))
        :else (filter predicate (rest sequence))))
(filter odd? (list 1 2 3 4 5))
(defn accumulate [op initial sequence]
  (if (null? sequence)
    initial
    (op (first sequence)
        (accumulate op initial (rest sequence)))))
(accumulate + 0 (list 1 2 3 4 5))
(accumulate * 1 (list 1 2 3 4 5))
(accumulate cons nil (list 1 2 3 4 5))
(defn enumerate-interval [low high]
  (if (> low high)
    nil
    (cons low (enumerate-interval (+ low 1) high))))
(enumerate-interval 2 7)
(defn enumerate-tree [tree]
  (cond (null? tree) nil
        (not (seq? tree)) (list tree)
        :else (concat (enumerate-tree (first tree))
                      (enumerate-tree (rest tree)))))
(enumerate-tree (list 1 (list 2 (list 3 4)) 5))
(defn sum-odd-squares [tree]
  (accumulate
   + 0 (map square (filter odd? (enumerate-tree tree)))))
(defn even-fibs [n]
  (accumulate
   cons nil (filter even? (map fib (enumerate-interval 0 n)))))
(defn list-fib-squares [n]
  (accumulate
   cons nil (map square (map fib (enumerate-interval 0 n)))))
(list-fib-squares 10)
(defn product-of-squares-of-odd-elements [sequence]
  (accumulate * 1 (map square (filter odd? sequence))))
(product-of-squares-of-odd-elements (list 1 2 3 4 5))
(letfn [(salary [] <??>)
        (programmer? [] <??>)]
  (defn salary-of-highest-paid-programmer [records]
    (accumulate max 0 (map salary (filter programmer? records)))))

;Exercise 2.23
(defn map-2.23 [p sequence]
  (accumulate (fn [x y] <??> nil sequence)))
(defn append-2.23 [seq1 seq2]
  (accumulate cons <??> <??>))
(defn length-2.23 [sequence]
  (accumulate <??> 0 sequence))

;Exercise 2.34
(defn horner-eval [x coefficient-sequence]
  (accumulate (fn [this-coeff higher-term] <??>)
              0
              coefficient-sequence))

;Exercise 2.35
(defn count-leaves-2.35 [t]
  (accumulate <??> <??> (map <??> <??>)))

;Exercise 2.36
(defn accumulate-n [op init seqs]
  (if (null? (first seqs))
    nil
    (cons (accumulate op init <??>)
          (accumulate-n op init <??>))))

;Exercise 2.37
(defn dot-product [v w]
  (accumulate + 0 (map * v w)))
(defn matrix-*-vector [m v]
  (map <??> m))
(defn transpose [mat]
  (accumulate-n <??> <??> mat))
(defn matrix-*-matrix [m n]
  (let [cols (transpose n)]
    (map <??> m)))

;Exercise 2.38
(def fold-right accumulate)
(defn fold-left [op initial sequence]
  (letfn [(iter [result rest-seq]
            (if (null? rest)
              result
              (iter (op result (first rest-seq))
                    (rest rest-seq))))]
    (iter initial sequence)))
(fold-right / 1 (list 1 2 3))
(try
  (fold-left / 1 (list 1 2 3))
  (catch Exception e))
(fold-right list nil (list 1 2 3))
(try (fold-left list nil (list 1 2 3))
     (catch StackOverflowError e))

;Exercise 2.39
(defn reverse-1 [sequence]
  (fold-right (fn [x y] <??>) nil sequence))
(defn reverse-2 [sequence]
  (fold-left (fn [x y] <??>) nil sequence))

;Nested Mappings
(let [n 4]
  (accumulate
   append nil (map (fn [i]
                     (map (fn [j] (list i j))
                          (enumerate-interval 1 (- i 1))))
                   (enumerate-interval 1 n))))
(defn flatmap [proc seq]
  (accumulate append nil (map proc seq)))
(defn prime-sum? [pair]
  (prime? (+ (first pair) (first (rest pair)))))
(defn make-pair-sum [pair]
  (list (first pair) (first (rest pair)) (+ (first pair) (first (rest pair)))))
(defn prime-sum-pairs [n]
  (map make-pair-sum
       (filter prime-sum? (flatmap
                           (fn [i]
                             (map (fn [j] (list i j))
                                  (enumerate-interval 1 (- i 1))))
                           (enumerate-interval 1 n)))))
(defn permutations [s]
  (letfn [(remove [item sequence]
            (filter (fn [x] (not (= x item))) sequence))]
    (if (null? s)
      (list nil)
      (flatmap (fn [x]
                 (map (fn [p] (cons x p))
                      (permutations (remove x s))))
               s))))

;Exercise 2.42
(letfn [(empty-board [] <??>)
        (safe? [] <??>)
        (adjoin-position [] <??>)]
  (defn queens [board-size]
    (letfn [(queen-cols [k]
              (if (= k 0)
                (list empty-board)
                (filter
                 (fn [positions] (safe? k positions))
                 (flatmap
                  (fn [rest-of-queens]
                    (map (fn [new-row]
                           (adjoin-position
                            new-row k rest-of-queens))
                         (enumerate-interval 1 board-size)))
                  (queen-cols (- k 1))))))]
      (queen-cols board-size))))

;Exercise 2.43
(comment
  (flatmap
   (fn [new-row]
     (map (fn [rest-of-queens]
            (adjoin-position new-row k rest-of-queens))
          (queen-cols (- k 1))))
   (enumerate-interval 1 board-size)))

;Chapter 2.2.4 A Picture Language
(declare wave beside flip-vert flip-horiz below up-split corner-split
         sub-vect make-vect add-vect origin-frame draw-line start-segment
         end-segment)
(defn flipped-pairs [painter]
  (let [painter2 (beside painter (flip-vert painter))]
    (below painter2 painter2)))
(comment
  (def wave2 (beside wave (flip-vert wave)))
  (def wave4 (below wave2 wave2))
  (def wave4 (flipped-pairs wave)))
(defn right-split [painter n]
  (if (= n 0)
    painter
    (let [smaller (right-split painter (- n 1))]
      (beside painter (below smaller smaller)))))
(defn up-split [painter n]
  (if (= n 0)
    painter
    (let [smaller (up-split painter (- n 1))]
      (below painter (beside smaller smaller)))))
(defn corner-split [painter n]
  (if (= n 0)
    painter
    (let [up (up-split painter (- n 1))
          right (right-split painter (- n 1))]
      (let [top-left (beside up up)
            bottom-right (below right right)
            corner (corner-split painter (- n 1))]
        (beside (below painter top-left)
                (below bottom-right corner))))))
(defn square-limit [painter n]
  (let [quarter (corner-split painter n)]
    (let [half (beside (flip-horiz quarter) quarter)]
      (below (flip-vert half half)))))
(defn square-of-four [tl tr bl br]
  (fn [painter]
    (let [top (beside (tl painter) (tr painter))
          bottom (beside (bl painter) (br painter))]
      (below bottom top))))
(defn flipped-pairs [painter]
  (let [combine4 (square-of-four identity flip-vert
                                 identity flip-vert)]
    (combine4 painter)))
(def rotate180 (comp flip-vert flip-horiz))
(defn square-limit [painter n]
  (let [combine4 (square-of-four flip-horiz identity
                                 rotate180 flip-vert)]))
(defn frame-coord-map [frame]
  (fn [v]
    (add-vect
     (origin-frame frame))))

;Exercise 2.47
(defn make-frame [origin edge1 edge2]
  (list origin edge1 edge2))

;Painters
(defn segments->painter [segment-list]
  (fn [frame]
    (for-each (fn [segment]
                (draw-line
                 ((frame-coord-map frame)
                  (start-segment segment))
                 ((frame-coord-map frame)
                  (end-segment segment))))
              segment-list)))
;Transforming and combining painters
(defn transform-painter [painter origin corner1 corner2]
  (fn [frame]
    (let [m (frame-coord-map frame)]
      (let [new-origin (m origin)]
        (painter (make-frame
                  new-origin
                  (sub-vect (m corner1) new-origin)
                  (sub-vect (m corner2) new-origin)))))))
(defn flip-vert [painter]
  (transform-painter painter
                     (make-vect 0.0 1.0)
                     (make-vect 1.0 1.0)
                     (make-vect 0.0 0.0)))
(defn shrink-to-upper-right [painter]
  (transform-painter
   painter (make-vect 0.5 0.5)
   (make-vect 1.0 0.5) (make-vect 0.5 1.0)))
(defn rotate80 [painter]
  (transform-painter painter
                     (make-vect 1.0 0.0)
                     (make-vect 1.0 1.0)
                     (make-vect 0.0 0.0)))
(defn squash-inwards [painter]
  (transform-painter painter
                     (make-vect 0.0 0.0)
                     (make-vect 0.65 0.35)
                     (make-vect 0.35 0.65)))
(defn beside [painter1 painter2]
  (let [split-point (make-vect 0.5 0.0)]
    (let [paint-left
          (transform-painter
           painter1
           (make-vect 0.0 0.0)
           split-point
           (make-vect 0.0 1.0))
          paint-right
          (transform-painter
           painter2
           split-point
           (make-vect 1.0 0.0)
           (make-vect 0.5 1.0))]
      (fn [frame]
        (paint-left frame)
        (paint-right frame)))))

Sunday, 8 January 2017

What Clojure is missing...

Ok, now I have played with Clojure for a lot of time.
I know how to write clojure programs, how to write in a functional style (on a base-medium level).
What is my main work, what kind of applications I build for my company... Web Applications, batch programs for some heavy computations. Our main application is built with Grails, and I can't say that I'm am so found on Grails..... buuut ....
Lately I built a web app to handle the deployment through Docker of our Web Application and I was thinking about using Clojure.
This is how the discussion went (more or less):
Marco: "I would like to use Clojure, is great, it gives immediate feedback and I would like to try because I feel I can do a good job"
Other People (in this company before starting we discuss pro and contro of every decision):
"Mmm I heard of it.. yes it can be an idea, but what are you going to use, what is the standard. Let's say that you start the application and then you have to move on another project, what should we start learning to be able to take over"
Marco: "Well I was thinking of using Luminus, it's quite well documented and it has already been used in production from what I know"
Others: "Ok, how are you going to divide the project? There are conventions like in Grails or Play Framework? You know is easier for new guys to join in a project if there are some standard rules"
Marco: "Mmm no there are some standard rules, I will organize the namespaces in the best way to be readable and easy for people to join in"
etc...

Unfortunately after this sentence I was not able to convince anymore my co-workers... and that's the reason for my post.
Grails, Spring Framework, Play Framework (Scala ..... one of the hardest language I ever studied) are standards that can be used in big companies. People that join the company and start work on the projects feels at home if they have already used them, for example in Grails they know that there will be a Controller, and then a Business Logic or a Model, but more or less they know how things will go, and will have the ability to join in the effort quite fast and without tutoring (or very less tutoring) because the documentation is really huge, and the approach Convention Over Configuration really help in this situation.
Clojure is missing a good framework with Convention Over Configuration, that explain also how to organize namespaces and that "force" developers that use it in a direction that is well documented and that can be easily grasp by new developers that join the project.
I have seen a lot of Clojure applications, and all of them have a very different approach in solving the problem that they face. If I have to start working on any of them, I fear I will need a lot of help to be productive.
It's true, I'm a Clojure and functional programmer Noob. But also when I will be a Pro Clojure programmer, my main concern will be, Clojure Noobs will soon join me, I want to easy their life, I want them to be productive.
I will continue my travel to become a Pro Clojure programmer, with this in mind, I have to create something that will give me the ability to reply to my co-workers:
"Yes this is the standard way to do things and can be easily learn from new people, this is the "Spring" framework of Clojure"
With something that set the standards on how to do Web Applications in Clojure, I'm sure this fantastic language will take more hype and attention in the future.

What is your idea? Have I missed a "De Facto" Standard guideline that explain how to write Web Apps in Clojure using a design model that is universally approved? I hope that the Arachne Framework will fix this issue but until documentation will be available I will not have a clue...

Friday, 6 January 2017

SICP in Clojure: Chapter 1

With a new year some new objectives should be set.

  1. Learn French
  2. Understand better functional programming
  3. Use Clojure in a real project (if you need help in some real project let me know :) )
This post is about the 2nd point. To learn more about functional programming I'm reading Structure and Interpretation of Computer Programs. This is really a great book but all the examples are in Lisp.
To make it more actual I'm rewriting all the examples in clojure (and some exercises too).  
I think it can be useful to others too, so here it is chapter 1:


(ns sicp.chapter-1)

;1.1 Expressions
(+ 137 349)
(- 1000 334)
(* 5 99)
(/ 10 5)
(+ 2.7 10)
(+ 21 35 12 7)
(* 25 4 12)
(+ (* 3 5) (- 10 6))
(+ (* 3 (+ (* 2 4) (+ 3 5))) (+ (- 10 7) 6))
(+ (* 3
      (+ (* 2 4)
         (+ 3 5)))
   (+ (- 10 7)
      6))

;1.2 Naming and the Environment
(def size 2)
size
(* 5 size)
(def pi 3.14159)
(def radius 10)
(* pi (* radius radius))
(def circumference (* 2 pi radius))
circumference

;1.1.3 Evaluating Combinations
(* (+ 2 (* 4 6))
   (+ 3 5 7))

;1.1.4 Compound Procedures
(defn square [x] (* x x))

;(defn <name> [<formal parameters>] <body>)
(square 21)
(square (+ 2 5))
(square (square 3))
(defn sum-of-squares
  [x y]
  (+ (square x) (square y)))
(sum-of-squares 3 4)
(defn f [a]
  (sum-of-squares (+ a 1) (* a 2)))
(f 5)

;1.1.5 The Substitution Model for Procedure Applincation
(f 5)
(sum-of-squares (+ 5 1) (* 5 2))
(+ (square 6) (square 10))
(+ 36 100)
(sum-of-squares (+ 5 1) (* 5 2))
(+ (square (+ 5 1)) (square (* 5 2)))
(+ (* (+ 5 1) (+ 5 1)) (* (* 5 2) (* 5 2)))
(+ (* 6 6) (* 10 10))
(+ 36 100)
(defn abs [x]
  (cond (> x 0) x
        (= x 0) 0
        (< x 0 ) (- x)))
(comment
  (cond <p1> <e1>
        <p2> <e2>
        ...
        <pn> <en>
        :else <e>))
(defn abs [x]
  (cond (< x 0) (- x)
        :else x))
(defn abs [x]
  (if (< x 0)
    (- x)
    x))
(comment
  (if <predicate>
    <consequent>
    <alternative>))
(comment
  (and <e1> .... <en>))
(comment
  (or <e1> ... <en>))
(comment
  (not <e>))
(comment (and (> x 5) (< x 10)))
(defn >= [x y]
  (or (> x y) (= x y)))
(defn >= [x y]
  (not (< x y)))
;Exercise 1.1
10
(+ 5 3 4)
(- 9 1)
(/ 6 2)
(+ (* 2 4) (- 4 6))
(def ^:private a 3)
(def ^:private b (+ a 1))
(+ a b (* a b))
(= a b)
(if (and (> b a) (< b (* a b)))
  b
  a)
(cond (= a 4) 6
      (= b 4) (+ 6 7 a)
      :else 25)
(+ 2 (if (> b a) b a))
(* (cond (> a b) a
         (< a b) b
         :else -1)
   (+ a 1))

;Exercise 1.2
(/ (+ 5
      4
      (- 2
         (- 3
            (+ 6
               (/ 4 5)))))
   (* 3
      (- 6 2)
      (- 2 7)))

;Exercise 1.3
(defn ex1-3
  [a b c]
  (cond
    (and (< a b) (< a c)) (+ (square b) (square c))
    (and (< b a) (< b c)) (+ (square a) (square c))
    :else (+ (square a) (square b))))

;Exercise 1.4
(defn a-plus-abs-b
  [a b]
  ((if (> b 0) + -) a b))

;Example 1.1.7
(defn good-enough? [guess x]
  (< (abs (- (square guess) x)) 0.001))
(defn average [x y]
  (/ (+ x y) 2))
(defn improve [guess x]
  (average guess (/ x guess)))
(defn sqrt-iter [guess x]
  (if (good-enough? guess x)
    guess
    (sqrt-iter (improve guess x) x)))
(defn sqrt [x]
  (sqrt-iter 1.0 x))
(sqrt 9)
(sqrt (+ (sqrt 2) (sqrt 3)))
(square (sqrt 1000))

;Exercise 1.6
(defn new-if [predicate then-clause else-clause]
  (cond
    predicate then-clause
    :else else-clause))
(new-if (= 2 3) 0 5)
(new-if (= 1 1) 0 5)
(defn new-sqrt-iter [guess x]
  (new-if (good-enough? guess x)
          guess
          (new-sqrt-iter (improve guess x) x)))
(defn new-sqrt [x]
  (new-sqrt-iter 1.0 x))

; (new-sqrt 9) -> Overflow

;Exercise 1.7
(good-enough?
 1000000000000000000000
 1000000000000000000000)
(good-enough? 1 1)
(defn new-good-enough? [prev-guess new-guess]
  (< (abs (- new-guess prev-guess)) 0.001))
(new-good-enough?
 1000000000000000000000
 1000000000000000000000)
(defn new-sqrt-iter-2 [guess x]
  (if (new-good-enough? guess (improve guess x))
    (improve guess x)
    (new-sqrt-iter-2 (improve guess x) x)))
(defn new-sqrt-2 [x]
  (new-sqrt-iter-2 1.0 x))
(new-sqrt-2 9)

;Exercise 1.8
(defn improve-cube-root [guess x]
  (/
   (+ (/ x (square guess))
      (* 2 guess))
   3))
(defn cube-root-iter [guess x]
  (if (new-good-enough? guess (improve-cube-root guess x))
    (improve-cube-root guess x)
    (cube-root-iter (improve-cube-root guess x) x)))
(defn cube-root [x]
  (cube-root-iter 3.0 x))
(cube-root 27)

;Chapter 1.1.8
(defn square [x] (* x x))
(defn double [x] (+ x x))
(defn square [x] (Math/exp (double (Math/log x))))
(square 3)
(defn sqrt [x]
  (letfn [(good-enough? [guess x]
            (< (abs (- (square guess) x)) 0.001))
          (improve [guess x] (average guess (/ x guess)))
          (sqrt-iter [guess x]
            (if (good-enough? guess x)
              guess
              (sqrt-iter (improve guess x) x)))]
    (sqrt-iter 1.0 x)))
(sqrt 9)
(defn sqrt [x]
  (letfn [(good-enough? [guess]
            (< (abs (- (square guess) x)) 0.001))
          (improve [guess] (average guess (/ x guess)))
          (sqrt-iter [guess]
            (if (good-enough? guess)
              guess
              (sqrt-iter (improve guess))))]
    (sqrt-iter 1.0)))
(sqrt 9)

;Chapter 1.2
(defn factorial [n]
  (if (= n 1)
    1
    (* n (factorial (- n 1)))))
(factorial 6)
(defn factorial [n]
  (letfn [(fact-iter [product counter max-count]
            (if (> counter max-count)
              product
              (fact-iter (* counter product)
                              (+ counter 1)
                              max-count)))]
    (fact-iter 1 1 n)))
(factorial 6)

;Execise 1.9
(letfn [(inc [x] (+ 1 x))
        (dec [x] (- x 1))]
  (defn + [a b]
    (if (= a 0) b (inc (+ (dec a) b))))
  (defn + [a b]
    (if (= a 0) b (+ (dec a) (inc b)))))
(def + clojure.core/+)

;Exercise 1.10
(defn A [x y]
  (cond
    (= y 0) 0
    (= x 0) (* 2 y)
    (= y 1) 2
    :else (A (- x 1) (A x (- y 1)))))
(A 1 10)
(A 2 4)
(A 3 3)
(letfn [(f [n] (A 0 n))
        (g [n] (A 1 n))
        (h [n] (A 2 n))
        (k [n] (* 5 n n))])

;Chapter 1.2.2
(defn fib [n]
  (cond
    (= n 0) 0
    (= n 1) 1
    :else (+ (fib (- n 1))
             (fib (- n 2)))))
(defn fib [n]
  (letfn [(fib-iter [a b count]
            (if (= count 0)
              b
              (fib-iter (+ a b) a (- count 1))))]
    (fib-iter 1 0 n)))
(fib 10)

;Example Counting Change
(defn first-denomination [kind-of-coins]
  (cond
    (= kind-of-coins 1) 1
    (= kind-of-coins 2) 5
    (= kind-of-coins 3) 10
    (= kind-of-coins 4) 25
    (= kind-of-coins 5) 50 ))
(defn cc [amount kind-of-coins]
  (cond
    (= amount 0) 1
    (or (< amount 0) (= kind-of-coins 0)) 0
    :else (+
           (cc amount (- kind-of-coins 1))
           (cc (- amount
                  (first-denomination kind-of-coins))
               kind-of-coins))))
(defn count-change [amount]
  (cc amount 5))
(count-change 100)
(count-change 200)

;Exercise 1.11
(defn f1-11 [n]   ;Recursive
  (if (< n 3)
    n
    (+ (f (- n 1))
       (* 2 (f (- n 2)))
       (* 3 (f (- n 3))))))

;Chapter 1.2.4
(defn expt [b n]
  (if (= n 0)
    1
    (* b (expt b (- n 1)))))
(expt 4 3)
(defn expt [b n]
  (letfn [(expt-iter [b counter product]
            (if (= counter 0)
              product
              (expt-iter b (- counter 1) (* b product))))]
    (expt-iter b n 1)))
(expt 4 3)
(defn fast-expt [b n]
  (cond
    (= n 0) 1
    (even? n) (square (fast-expt b (/ n 2)))
    :else (* b (fast-expt b (- n 1)))))
(fast-expt 4 3)

;Exercise 1.19
(comment
  (defn fib [n]
    (letfn [(fib-iter [a b p q count]
              (cond
                (= count 0) b
                (even? count) (fib-iter a
                                        b
                                        <??>
                                        <??>
                                        (/ count 2))
                :else (fib-iter (+ (* b q) (* a q) (* a p))
                                (+ (* b p) (* a q))
                                p
                                q
                                (- count 1))))])))

;Chapter 1.2.5 Greatest Common Divisors
(defn gcd [a b]
  (if (= b 0)
    a
    (gcd b (rem a b))))

;Chapter 1.2.6 Example: Testing for Primality
(defn smallest-divisor [n]
  (letfn [(divides? [a b]
            (= (rem b a) 0))
          (find-divisor [n test-divisor]
            (cond
              (> (square test-divisor) n) n
              (divides? test-divisor n) test-divisor
              :else (find-divisor n (+ test-divisor 1))))]
    (find-divisor n 2)))
(defn prime? [n]
  (= n (smallest-divisor n)))

;Fermat Test
(defn expmod [base exp m]
  (cond
    (= exp 0) 1
    (even? exp) (rem
                 (square (expmod base (/ exp 2) m))
                 m)
    :else (rem
           (* base (expmod base (- exp 1) m))
           m)))
(defn fermat-test [n]
  (letfn [(try-it [a]
            (= (expmod a n n) a))]
    (try-it (+ 1 (rand (- n 1))))))
(defn fast-prime? [n times]
  (cond
    (= times 0) true
    (fermat-test n) (fast-prime? n (- times 1))
    :else false))

;Exercise 1.21
(smallest-divisor 199)
(smallest-divisor 1999)
(smallest-divisor 19999)

;Exercise 1.22
(defn runtime [] (System/currentTimeMillis))
(defn timed-prime-test [n]
  (letfn [(report-prime [elapsed-time]
            (letfn []
              (println " *** ")
              (println elapsed-time)))
          (start-prime-test [n start-time]
            (if (prime? n)
              (report-prime (- (runtime) start-time))))]
    (println "")
    (println n)
    (start-prime-test n (runtime))))

;Exercise 1.25
(defn expmod [base exp m]
  (rem (fast-expt base exp) m))

;Exercise 1.26
(defn expmod [base exp m]
  (cond
    (= exp 0) 1
    (even? exp) (rem (* (expmod base (/ exp 2) m)
                        (expmod base (/ exp 2) m))
                     m)
    :else
    (rem (* base
            (expmod base (- exp 1) m))
         m)))

;Chapter 1.3
(defn cube [x] (* x x x))

;Chapter 1.3.1
(defn sum-integers [a b]
  (if (> a b)
    0
    (+ a (sum-integers (+ a 1) b))))
(defn sum-cubes [a b]
  (if (> a b)
    0
    (+ (cube a)
       (sum-cubes (+ a 1) b))))
(defn pi-sum [a b]
  (if (> a b)
    0
    (+ (/ 1.0 (* a (+ a 2)))
       (pi-sum (+ a 4) b))))
(defn sum [term a next b]
  (if (> a b)
    0
    (+ (term  a)
       (sum term (next a) next b))))
(defn inc [n] (+ n 1))
(defn sum-cubes [a b]
  (sum cube a inc b))
(sum-cubes 1 100)
(defn sum-integers [a b]
  (letfn [(identity [x] x)]
    (sum identity a inc b)))
(sum-integers 1 5)
(defn pi-sum [a b]
  (letfn [(pi-term [x] (/ 1.0 (* x (+ x 2))))
          (pi-next [x] (+ x 4))]
    (sum pi-term a pi-next b)))
(* 8 (pi-sum 1 1000))
(defn integral [f a b dx]
  (letfn [(add-dx [x] (+ x dx))]
    (* (sum f (+ a (/ dx 2.0)) add-dx b)
       dx)))
(integral cube 0 1 0.01)
(integral cube 0 1 0.001)

;Chapter 1.3.2 Constructing Procedures Using lambda
(fn [x] (+ x 4))
#(+ % 4)
(fn [x] (/ 1.0 (* x (+ x 2))))
#(/ 1.0 (* % (+ % 2)))
(defn pi-sum [a b]
  (sum #(/ 1.0 (* % (+ % 2)))
       a
       #(+ % 4)
       b))
(defn integral [f a b dx]
  (* (sum f
          (+ a (/ dx 2.0))
          #(+ % dx)
          b)
     dx))
(comment  (<fn> [<formal-parameters] <body>) or #(<body> with % as x))
(defn plus4 [x] (+  x 4))
(def plus4 #(+ % 4))
(#(+ %1 %2 (square %3)) 1 2 3)

;Using let to create local variables
(defn f [x y]
  (letfn [(f-helper [a b]
            (+ (* x (square a))
               (* y b)
               (* a b)))]
    (f-helper (+ 1 (* x y))
              (- 1 y))))
(f 1 2)
(defn f [x y]
  ((fn [a b]
     (+ (* x (square a))
               (* y b)
               (* a b)))
   (+ 1 (* x y))
   (- 1 y)))
(f 1 2)
(defn f [x y]
  (let [a (+ 1 (* x y))
        b (- 1 y)]
    (+ (* x (square a))
       (* y b)
       (* a b))))
(f 1 2)
(let [x 5]
  (+ (let [x 3]
       (+ x (* x 10)))
     x))
(let [x 2]
  (let [x 3
        y (+ x 2)]
    (* x y)))
(defn f [x y]
  (let [a (+ 1 (* x y))
        b (- 1 y)]
    (+ (* x (square a))
       (* y b)
       (* a b))))

;Chapter 1.3.3 Procedures as General Methods
(defn close-enough? [x y]
  (< (abs (- x y)) 0.001))
(defn search [f neg-point pos-point]
  (let [midpoint (average neg-point pos-point)]
    (if (close-enough? neg-point pos-point)
      midpoint
      (let [test-value (f midpoint)]
        (cond
          (pos? test-value) (search f neg-point midpoint)
          (neg? test-value) (search f midpoint pos-point)
          :else midpoint)))))
(defn error [s v1 v2]
  (println (str s " " v1 " " v2 )))
(defn half-interval-method [f a b]
  (let [a-value (f a)
        b-value (f b)]
    (cond
      (and (neg? a-value) (pos? b-value)) (search f a b)
      (and (neg? b-value) (pos? a-value)) (search f b a)
      :else (error "Values are not of opposite sign" a b))))
(def sin #(Math/sin %))
(def cos #(Math/cos %))
(half-interval-method sin 2.0 4.0)
(half-interval-method #(- (* % % %) (* 2 %) 3) 1.0 3.0)

;Finding fixed points of functions
(def tolerance 0.00001)
(defn fixed-point [f first-guess]
  (letfn [(close-enough? [v1 v2]
            (< (abs (- v1 v2)) tolerance))
          (try-f [guess]
            (let [next (f guess)]
              (if (close-enough? guess next)
                next
                (try-f next))))]
    (try-f first-guess)))
(fixed-point #(+ (sin %) (cos %)) 1.0)
(defn sqrt [x]
  (fixed-point #(/ x %)
               1.0))
(defn sqrt [x]
  (fixed-point #(average % (/ x %))
               1.0))

;Chapter 1.3.4 Procedures as Returned Values
(defn average-damp [f]
  #(average % (f %)))
((average-damp square) 10)
(defn sqrt [x]
  (fixed-point (average-damp #(/ x %))
               1.0))
(defn cube-root [x]
  (fixed-point (average-damp #(/ x %))
               1.0))
(def dx tolerance)
(defn- deriv [g]
  #(/ (- (g (+ % dx))
         (g %))
      dx))
(defn cube [x] (* x x x))
((deriv cube) 5)
(defn newton-transform [g]
  #(- % (/ (g %) ((deriv g) %))))
(defn newtons-method [g guess]
  (fixed-point (newton-transform g) guess))
(defn sqrt [x]
  (newtons-method
   #(- (square %) x) 1.0))
(defn fixed-point-of-transform [g tranform guess]
  (fixed-point (tranform g) guess))
(defn sqrt [x]
  (fixed-point-of-transform #(/ x %) average-damp 1.0))
(defn sqrt [x]
  (fixed-point-of-transform
   #(- (square %) x) newton-transform 1.0))


Wednesday, 21 January 2015

Light Table

Ok after some work with it I have to say that it's really one of the easiest IDE to start with Clojure.
The auto complete is very well done and is the only ide that make possible to start trying clojure without any issue with the IDE.
ps: if you create a leiningen project LightTable will use the clojure version that you set in it, by default it will instead use the clojure 1.5.1