Don’t panic! [Clojure version]

Hi guys!
When it rains my internet connection is a pain in the neck, by the way I want to show you the Clojure version of Don’t Panic.
If you don’t remember it, Don’t Panic is a simple application developed with university students in mind, it periodically checks a site, looking for an update. It was a good occasion to play with Leningen!
Here is the full code (Leningen version):

;; Don't panic
(ns dontpanic.core (:gen-class))

(defn fetch-url
  "Fetches an URL. Returns a string made by the page's html."
  [address]
  (with-open [stream (.openStream (java.net.URL. address))]
    (let  [buf (java.io.BufferedReader.
		(java.io.InputStreamReader. stream))]
      (apply str (line-seq buf)))))

(defn hash-code
  "Simple wrapper. Returns a string hashcode."
  [string]
  (.hashCode string))

(defn -main
  "Periodically check if a site has been modified."
  [& args]
  (let
      [address (nth args 0)
       site-hashcode (hash-code (fetch-url address))]
    (while true
       (do
	 (if (not (= site-hashcode (hash-code (fetch-url address))))
	   (println "Maybe an update! Finger crossed.")
	   (println "Nothing changed, calm down."))
	 (Thread/sleep 5000)))))

The idea behind the scenes is very simple: fetch-url returns the entire page’s html as a string, the hash-code function returns the string hash code. The eternal loop (while true) fetch the url, computes the hash code: if it’s different from the previous one, an maybe an update is occurred!
Shortly I will post a standalone jar!!
Usage (code version):

(-main [<site url as string>])

Usage (jar version):

java -jar dontpanic.jar <site-url>

Enjoy!

Annunci

Fun with Clojure and MongoDB

Personally I think that writing SQL queries is the most boring task in the IT world, because there exists a large variety of software elements (have you ever heard the word ORM?) that do the job for you.
Since Clojure have no objects, so no impedance mismatch, I thoughtย it would be interesting to combine the Clojure learning and the everyday use with a NoSQL database, such as MongoDB.
There are no particular reasons why I’ve choose MongoDB, but it seems to me quite well-written and easy to use. Clojure provides a simple wrapper to the MongoDB API, the module is called congomongo, and it is installable via leningen in the usual way (add a line into the dependency section of your project.clj).

Remember to start mongod!

Like most databases in the world, MongoDB needs a deamon to dispatch the request to the database: such deamon’s name is mongod. Once installed MongoDB start mongod from console: now your applications can talk with MongoDB.

Fun with Clojure

The following code has the purpose to show some simple operations of fetch, insert and fetch with conditions:

;;Fun with MongoDB
(ns mongofun
  (:use somnium.congomongo))

;;It tells to mongo wich DB you want to use/create
(mongo! :db "mongofun")

;; A simple insert, you have to pass a map of key-value
(insert! :exams {:name "OOP" :vote 29})

;; A simple binding used to show all your exams
(def my-exams (fetch :exams))

;; A general purpose function for inserting an exam
(defn insert-exam [exam-map]
     (insert! :exams exam-map))

;; A list of maps, 1 map = 1 exam
(def exams-list [{:name "Computer Graphics" :vote 30}
		  {:name "IA" :vote 30}
		  {:name "BD2" :vote 30}])

;; Loop over exams-list, insert all the exams
(for [e exams-list] (insert-exam e))

;;Retrieve all the exams where I've took 30
(fetch :exams :where {:vote 30})

This is only a short snipped, but the interesting things is that I haven’t wrote a single line of SQL.
You can see all the exams with my-exams func.
Bye!

Alfredo

[Clojure] Project Euler Problem 5 solution

For par condicio I have to show you the same problem solution but in my favorite language, Clojure.
Once again, it seems to me the coolest-freaking-awesome functional language in the world:

(defn div-1-20? [x]
  (defn aux [x acc]
    (cond
     (= x 0) false
     (= 0 acc) true
     (= 0 (mod x acc)) (aux x (dec acc))
     :else false))
  (aux x 20))

(first (filter div-1-20? (range)))

Even this solution runs in constant space, due to the range that generates a lazy sequence.
I love Clojure โค

Bye!
Alfredo

References:

Racket vs Clojure

[Racket/Scheme] Project Euler Problem 5 Solution

Ok ok, I have to admit that Racket is pretty cool sometimes ๐Ÿ˜€ (despite it’s very verbous :D)
This is my solution for the problem 5:

#lang racket

(define (div-1-20? x)
  (let aux ([x x]
            [acc 1])
            (cond
              [(= 0 x) #f]
              [(= 21 acc) #t]
              [(= 0 (modulo x acc)) (aux x (add1 acc))]
              [else #f])))

;; Pretty cool
(for ([i (stop-after (in-naturals 1) div-1-20?)]
      #:when (div-1-20? i)) (display i))

The dark magic is provided by in-naturals, stop-after and the #:when clausole:

  • in-naturals provide a lazy sequence from start to +inf
  • stop-after make sure that for will stop when the predicate div-1-20? will be satisfied
  • when assures that only when div-1-20? will be satisfied the for body will be executed

As result this code runs in constant space and is no memory-consuming at all ๐Ÿ™‚

Bye!

Alfredo

[Project Euler Problem 4 Solution] Thanks God, Clojure exists!!

I’ve tried several functional languages (OCaml, Haskell, Racket/Scheme) but Clojure is pure awesomeness.
This is a semi-trivial, not optimized solution to the problem 4 of Project Euler.
Note: you need the pattern-match jar, a wonderful way to bring pattern matching into your Clojure functions.
You can download it from Clojars or adding a dependency in Leningen:

(use 'pattern-match)

(defn palindrome? [num-as-string]
  (match num-as-string
	 [] true
	 [x] true
	 [x x] true
	 [x & xs] (if (= x (last xs)) (palindrome? (butlast xs)) false)
	 _ false))

(sort (map (fn [x] (Integer. x))
	   (filter palindrome?
		   (for [n1 (range 100 999)
			 n2 (range 100 999) :let [k (* n1 n2)]] (str k)))))

In my opinion this version is very readable even if you are a beginner:

  • The nested for iter over two range, binding k to (* n1 n2), building a list of strings
  • The resulting list is passed to the filter function with the predicate palindrome? that checks if a number is palindrome
  • The outer map convert such filtered list in a integer list
  • The final sort sort the results because the problem wants the largest palindrome number

Bye!

Alfredo

A minimalistic implementation of the Hangman game in Haskell

Hello everyone,
I was just playing around with Haskell and I’ve realized a simple Hangman game.
I’m very new with Haskell, so I’ve certainly made some mistakes ๐Ÿ™‚

Here’s the code:

import System.IO

revealChar (x:[]) secretWord partialWord =
           zipWith (\ s p -> if x == s then s else p) secretWord partialWord
revealChar xs secretWord partialWord =
           if xs == secretWord then secretWord else partialWord

getSecretWord = do
              sBuff <- openFile "secretWords.txt" ReadMode
              inpStr <- hGetLine sBuff
              hClose sBuff
              return inpStr

playGame 0 secret partial = do putStrLn "I'm sorry, you have lose!"
playGame t secret partial = do
          putStrLn $ "=> " ++ partial
          putStrLn $ "Tell the a single letter or the entire word. " ++ (show t) ++ " tries left."
          charStr <- getLine
          if secret == partial
             then putStrLn "You have win!"
             else playGame (t-1) secret (revealChar charStr secret partial)

main = do
     secretWord <- getSecretWord
     let partialWord = foldl1 (++) (replicate (length secretWord) "_")
     putStrLn "Welcome to the useless Hangman Game!"
     putStrLn ("Today's word is: " ++ partialWord)
     playGame (length partialWord) secretWord partialWord</pre>

I must confess, I begin to like Haskell and his weird syntax. This version is very readable and compact in my opinion. There are some tricks of FP I want to show you in this code:

  1. The pattern matching magic allows the revealChar function to be reusable to both guess entire word or check a single character. Maybe revealChar it’s a violation of the FP pure functions?
  2. Anonimous functions are in my opinion a very elegant way to make your code smaller and cleaner.
  3. The secret word is stored in a separate file, so no spoiler at all ๐Ÿ™‚
  4. You can run this saving it into a .hs file and running runghc <yourfile>

I’m looking forward to go deeper in Haskell ๐Ÿ™‚

Bye,
Alfredo