Head into Clojure – Part 2: The Basic Types

More Clojure-ness code examples. This time some basic types, collections and sequences


; Basic Types

;; Chars
;; Clojure represents all chars in with a leading \
(char 97)					;; Returns \a, 97 being ASCII a
(char? \a)					;; true
(char? (char 97))				;; true

;; Strings
“This is a string”				;; Define a string, uses double quotes “…”
(string? "Are you a string")			;; Check if a string
(println "Hello world")				;; Print a string out
print-str
println-str
pr-str
prn-str
(with-out-str (println "this should return as a string"))
(subs "1234" 1)
(subs “abcdef” 1 2)
(count “1 2 3 4”)				;; Counts the number of chars in a string

;; Collections and Sequences

;; For a good description about the difference ( mainly in your head ) between Clojure collections
;; and sequences, head over to http://www.brainonfire.net/files/seqs-and-colls/main.html
;; What you need to get your head round is every sequence is a collection, but not every collection is a sequence.

;;; Lists					;; Linked List
(+ 1 2 3)					;; List, function as first item, evaluates to 6
‘( 1 2 3 4 )					;; List, made up of 4 items
(list 1 3 4 5)					;; Another way to produce a list
(def my-list ‘(1 2 3))				;; List, assigned to variable my-list

;;; Vectors
[1 2 3]						;; Vector of 3 items
[[1 2] [3 4] [5 6]]				;; Vector of 3 Vectors
(vector 1 2 3)					;; Another way to create a vector
(def my-vector [1 2 3 4])			;; Assign vector of 4 times to variable my-vector
(my-vector 2)					;; Access 3rd element ( vectors zero based )
(get my-vector 0)                               ;; 1
(get my-vector 2)                               ;; 3
(get my-vector 10)                              ;; nil

;;; Maps					;; value to value
{ 1 2 3 4 }					;; Create a vector or 2 elements, 1 => 2 and 3 => 4
						;; Creating maps always needs an even number of elements
(def my-map {1 2 3 4})
(my-map 1)					;; Returns value with key 1
(my-map 5)					;; Returns nil
(def my-map {:name "fred" :age 32})		;; Map with keywords
(my-map :name)					;; Access map via keyword
(get my-map :name)                              ;; fred
(def my-map2 {“name” "fred" “age” 32})		;; Map with strings as keys
(my-map2 “name”)				;; Access map via str key

;;; Sets					;; Sets - List of unique values, no duplicates
#{1 2 3 4}                                      ;; Defined using #{..}
(set [1 2 3 4 5 6])				;; Results in a set of 6 items 1, 2, 3, 4, 5 and 6
(set [1 2 2 1 1 2])				;; Results in a set of 2 items 1 and 2
(my-set 1)
(get my-set 1)

;; Manipulation Collections

(first '(1 2 3))				;; Get the first element of a list
(first [1 2 3])					;; Get the first element of a Vector
(first {1 2 3 4})				;; Get the first element of a value map
(first {:first 1 :second 2})			;; Get first element of keyword map, but which gets
						;; returned is indeterminate because you don’t know
						;; internally how the map is stored in order

(rest '(1 2 3))					;; Get all but the first element of a list
(rest [1 2 3])					;; Get all but the first element of a Vector
(rest {1 2 3 4})				;; Get all but the first element of a value map
(rest {:first 1 :second 2})			;; Get all but the first element of keyword map, 
						;; but which gets returned is indeterminate because 
						;; you don’t know internally how the map is stored in order

(cons 1 '(2 3 4))				;; Add element to front of list	
(cons 1 [2 3 4])				;; Add element to front of Vector

Head into Clojure – Part 1: The Basics

I love reading books and I love learning programming languages, but I’ve found that I don’t like reading books to learning programming languages. This is especially true for some of the new languages, specifically Scala and Clojure. Yes you can read a multitude of acronym vebosities as an author tries and shows you just how many words they can type to help explain a feature, but I would rather just have the core basics, explained via lots of examples.

If you have read any of the the Little Schemer books, which are just a set of examples getting increasingly more complex, or have checked out any of the learnxinyminutes.com pages, then you will find this article ( and the subsequent ones ), very similar. I found I learn by example, and as I learn a new language I write down examples of each of the features as I learn them.

These notes are how I learnt Clojure and built my first apps with it.

First lets get some basic terminology out of the way, specifically atoms, s-expressions and forms. In Clojure code is made up of s-expressions, and s-expressions are recursively made up of either an s-expression or an atom

An atom is the most basic of types, an immutable object that always resolves to itself, typically a scala type such as an integer, float, string or char


1                         ;; Integer atom
2.3                       ;; Float atom
"keith"                   ;; String atom
\b                        ;; Char atom

An s-expressions is sequence of data surrounded by parantheses that is evaluated by the Clojure interpreter. For a generic definition see Wikipedia, which states

In computing, s-expressions, sexprs or sexps (for “symbolic expression”) are a notation for nested list (tree-structured) data, invented for and popularized by the programming language Lisp, which uses them for source code as well as data.

And from Clojure.org itself, they are defined as:

Clojure programs are composed of expressions. Every form not handled specially by a special form or macro is considered by the compiler to be an expression, which is evaluated to yield a value. There are no declarations or statements, although sometimes expressions may be evaluated for their side-effects and their values ignored.

Clojure works by taking an s-expressions, a list of data surrounded by () and assumes the first element in the list is a function. It then applies the function the remaining items of data in the list. In Clojure this is called a form. The only deviation from this rule is for either special forms and macros, both we’ll talk about later as we come across them and now neccassary at this stage


; This is a comment, in Clojure all single line comments start with a ';'

;; However the Clojure community seems to prefer the use of double ';;' instead
;;; However this is a comment
;;;; And so is this
;;;;;;;;; Clojure basically ignores everything after the first ;

;; For more details on a community attempt to document Clojure code, head over
;; to https://clojuredocs.org/

;; There are other ways to comments code out and we'll come across that as we
;; move through this tutorial

;; Before you can even start using Clojure you need to get an instance running
;; Clojure runs on top of the Java virtual machine, so first you need to install
;; an appropriate JVM. 
;; This can be downloaded from Oracle https://www.java.com/en/download/
;; Clojure needs atleast Java 6 SDK to run

;; Once installed and running you then need to download the latest Clojure from
;; http://clojure.org/downloads

;; The first way we will use Clojure is through the native REPL, which stands for
;; Read, Evalutate, Print, Loop
;; This provides a command line interface that you can execute Clojure commands from

;; To run the REPL, execute the following command from the command line
;; java -cp /Clojure-1.6.0/clojure-1.6.0.jar clojure.main

; Get Help

;; Before we get started you are going to want more help that these files produce
;; The primary source of all Clojure info is at
;; http://clojure.org/
;; This tutorial is heavily based on the learn x in y minutes pages at
;; http://learnxinyminutes.com/docs/clojure/
;; The primary difference being its structure the way I think and learnt Clojure
;; which builds from first principles as a pure Lisp language and then introduces
;; the additional complexity added by he Java Virtual Machine
;; When you really just need help on syntax, or just need to remember the name
;; of a command then your first stop should be
;; http://clojure.org/cheatsheet

; Getting started

;; Clojure is a Lisp, a member of a family of languages, including Scheme, Common Lisp
;; Lisp ( and therefore Clojure ) are built around the basic concept of a list of things
;; more commonly called forms

;; Forms are bounded by brackets either () or [] and contain zero or more items which
;; make up the list

;; Typically Clojure ( and all Lisps ) assume that the first element of a list is a
;; function call, and all other elements are parameters which are passed to the
;; function

;; The most basic of functions are the basic arithmetic, + - * /, e.g

(+ 2 2)                            ;; Add 2 and 2, returning 4
(* 1 2 3)                          ;; Multiple 1, 2 and 3, returning 6

;; If you don't want Clojure to interpret your form, then you can quote it with either the
;; character ' or the function 'quote'

'(+ 2 2)                           ;; All elements of the form are taken as a list
                                   ;; In this instance creates a list of 3 items

(quote (+ 2 2))                    ;; Identical to the above

;; If we want to evaluate a list of elements, we can use the function 'eval'

(eval '(+ 2 2))                    ;; Returns the value 4

;; The examples for quote and eval above show the use of nested lists
;; Each element of a list can be an individual item or a list itself
;; Lists are evaluated to a single item as the list is interpreted

(+ (* 2 3) (* 4 2))                ;; Becomes (+ 6 8)
                                   ;; Which becomes 14

;; There is not limited to the depth of nesting in Lisp

(+ (+ (+ 2 2 ) 3) 4)

;; Whitespace and commas
;; Its worth exploring how Clojure ( and Lisp ) uses whitespace to separate
;; elements of the list, and how commas ',' can be used to show individual
;; items but are ignore by the interpreter

;; Maths Operators
(+ 2 2)
(- 1 2)
(* 2 3)
(/ 4 2)
(quot 3 2)                         ;; quot[ient] of dividing numerator by denominator. Returns 1
(rem 3 2)                          ;; remainder of dividing numerator by denominator
(mod 2 3)                          ;; Modulus of num and div
(inc 2)                            ;; Increments the number by 1
(dec 3)                            ;; Decrements the number by 1
(max 3 5 7)                        ;; Maximum number in list
(min 2 4 1 7)                      ;; Minimum number in list

;; Boolean operations
;; In Clojure, boolean True is represented as true and boolean False as false
;; Everything except `false' and `nil' is true in boolean context.
;; In Clojure nil means 'nothing', and is not the same as (), the empty set

;; Comparison operators
;;; =                               ;; Compares if the 2 elements are the same and the same value
(= 2 2)                             ;; true
(= 2 2.0)                           ;; false
;;; ==                              ;; Compares the numeric value, true if equals
(= 2 2)                             ;; true
(= 2 2.0)                           ;; true
(not= 2 3)                          ;; Not equal to each other
(< 1 2 3)                           ;; Tests first element is less than all others 
(> 2 3 4)                           ;; Tests first element is less than all others
(<= 4 4)                            ;; Tests first element is less than or equal to all others 
(>= 6 5 5)                          ;; Tests first element is great than or equal to all others
(compare 3 4)                       ;; Returns a negative number, zero, or a positive number
                                    ;; when x is logically 'less than', 'equal to',
                                    ;; or 'greater than' y

;; Tests. Unary methods that test the value of a result. Return true or false
(zero? 1)                           ;; Is the number 0, true or false
(pos? -1)                           ;; Is the number postive, true or false
(neg? 1)                            ;; Is the number negative, true or false
(even? 2)                           ;; Is the number even, true or false
(odd? 3)                            ;; Is the number odd, true or false
(number? 'hello')                   ;; Is the number a number, true or false
(rational? 1.                       ;; Is the number a rational ( not a decimal ), true or false
(integer? 1.3)                      ;; Is the number an integer, true or false
(ratio? 22/7)                       ;; Is the number a decimal number expressed as a ratio, true or false
(decimal? 1.4)                      ;; Is the number a decimal number not expressed as a ratio, true or false
(float? 3)                          ;; Is the number a floating point number, true or false

So thats it, thats a real basic introduction to Clojure, next lesson will introduce you to functional programming. After all isn’t that why you are learning Clojure, its all about the functions !

Once we get your head into functional programming we look at core types of Lists, Vectors, Sets and Maps, and we use functional programming to manipulate them

Working with INI files in Python

Quite often you want to extract you configuration data into a config file, the Windows INI is still a popular format, well understood by most people who like to get their hands dirty on the command line.
When using ini files, you basically want to do 3 things

  • Pass the name of the config file as a command line arg, printing something useful if the arg is missing
  • Load the contents of the init file and use them

This little code snippet does the lot in one go

import configparser
import os.path
from optparse import OptionParser

config  = ["-c", "--config", "config", "Configuration File, INI format"]
parser = OptionParser()
parser.add_option(config[0], config[1], dest=config[2], help=config[3])
(options, args) = parser.parse_args()
if None == options.config:
    parser.print_help ()
    exit(0)
if not os.path.isfile(options.config):
    exit(0)
    parser.print_help ()

config_file = configparser.ConfigParser(interpolation=None)
config_file.read(options.config)

Basically, import the necessary libraries, then set up the Command Line arg, in this instance -c, but you can add more by calling add_option() with new values

Next call parser.parse_args() to parse the command line args passed to you app. If nothing is there, or ‘config’ is missing, or not a valid file, then bomb out print useful help text

Finally load the ini file by using ConfigParser. I use ‘interpolation=None’ so that the parser does not substitute variables inside the ini allowing me to use $ and other non alpha numeric characters where needed

Simple Client/Server RESTful Services with Python

In this article we look at creating the basics of a RESTful service and associated client, that we’ll build on later to create our home automation server

First we need to make sure we have a couple of libraries installed, specifically httplib2 and Flask. Install them using pip

sudo pip install httplib2
sudo pip install Flask

We can check they are installed with

pip list

which should display a list which includes the following

$ pip list
Flask (0.10.1)
httplib2 (0.8)

RESTFul Server

First the server, which we build using Flask

from flask import Flask, request, json
from pymongo import MongoClient

app = Flask(__name__)
mongo_client = MongoClient()
mongo_client['HomeControl'].temperature.drop ()

@app.route("/homecontrol/api/v1.0/temperature", methods=['POST'])
def api_temperature():
    if request.headers['Content-Type'] == 'text/plain':
        print (request.data)
        return 'OK', 200
    elif request.headers['Content-Type'] == 'application/json':
        print (json.dumps(request.json))
        mongo_client['HomeControl']['temperature'].insert(request.json)
        print (mongo_client['HomeControl']['temperature'].count ())
        return "OK", 200
    else:
        return "Unsupported Media Type", 415

if __name__ == '__main__':
    app.run(debug = False)

For a description of how to create a RESTFul server in Flask, check out the excellent blog by Miguel Grinberg

RESTFul Client

Then a basic client that emulates our temp server

import httplib2
import json
import time
import datetime

if __name__ == '__main__':

    httplib2.debuglevel     = 0
    http                    = httplib2.Http()
    content_type_header     = "application/json"

    url = "http://127.0.0.1:5000/homecontrol/api/v1.0/temperature"

    data = {    'room':         "Living Room",
                'temp':         23.45,
                'humidity':     50.00,
                'timestamp':    str(datetime.datetime.now())
           }

    headers = {'Content-Type': content_type_header}
    print ("Posting %s" % data)

    while True:
        response, content = http.request( url,
                                          'POST',
                                          json.dumps(data),
                                          headers=headers)
        print (response)
        print (content)
        time.sleep(3)

This simple client sits in a loop posting a JSON object to our server every 3 seconds
We’ll fill out this client as time goes by, hooking it up to real temp sensors on the pi

Room Temperature Sensor With Raspberry Pi

This article is taken from the following web pages, with a few modifications by me.

The intention is to create a Raspberry monitoring station for each room in the house, each broadcasting temperature and other information back to a central server in my office.

To start with I am using DS18B20 temperature sensor, which you can get from Amazon and eBay for about 50p-£1 each.

Along with the sensor you are going to need a breadboard, ribbon cable, some wires and 4.7k resistor

breadboard-ic.png

Once you have this wired up, you need to activate the sensor

$ sudo modprobe w1-gpio
$ sudo modprobe w1-therm
$ cd /sys/bus/w1/devices
$ ls

This will give you the id of the device starting 28- and looking something like

28-xxxxxxxxxxxxxxx

Now create a shell script we can query the sensor

nano ~/temp.sh

And add the following lines

#! /bin/bash
sudo modprobe w1-gpio
sudo modprobe w1-therm
roomtemp=$(cat /sys/bus/w1/devices/28-xxxxxxxxxxxx/w1_slave | grep  -E -o ".{0,0}t=.{0,5}" | cut -c 3-)
echo "Temperature: $roomtemp"

To make it executable, give it +x permissions

chmod +x ~/temp.sh

And it will print out the temp, device / 1000 for ‘C

$ ~./temp.sh
186903

Which is 18.69’C

Now lets create a little Python script that parses the data and loops printing out the value every 10 secs

nano ~/temp.py

And add the following lines

import time
while True:
        # Open the file that we viewed earlier so that python 
        # can see what is in it. Replace the serial number as before.
        tfile = open("/sys/bus/w1/devices/28-xxxxxxxxxx/w1_slave")
        # Read all of the text in the file.
        text = tfile.read()
        # Close the file now that the text has been read.
        tfile.close()
        # Split the text with new lines (\n) and select the second line.
        secondline = text.split("\n")[1]
        # Split the line into words, referring to the spaces, 
        # and select the 10th word (counting from 0).
        temperaturedata = secondline.split(" ")[9]
        # The first two characters are "t=", so get rid of those and 
        # convert the temperature from a string to a number.
        temperature = float(temperaturedata[2:])
        # Put the decimal point in the right place and display it.
        temperature = temperature / 1000
        print ("%2.2f'C" % temperature)
        time.sleep(10)

To run the script, use

python temp.py

Mine is currently showing a balmy 16-19’C in my office

19.00'C
18.94'C
19.06'C
18.81'C
18.12'C
18.12'C
18.50'C
18.56'C
18.06'C
18.06'C
18.25'C
18.06'C
17.69'C
17.81'C
17.25'C
17.12'C
16.69'C
16.31'C
16.50'C
16.81'C
17.12'C
17.38'C
17.56'C
17.56'C

Loading Drivers on Startup

The following lines are taken from raspberry.znix.com

sudo nano /etc/modprobe.d/raspi-blacklist.conf and comment out the following 2 lines

blacklist spi-bcm2708
blacklist i2c-bcm2708

sudo nano /etc/modules

w1-gpio
w1-therm

Next steps

Now that we have a temperature sensor schematic and working prototype, need to build 3 or 4 more, and then hook them up to the central server. So once they are built, I need a Restful service that each of the Pi’s can call with their temperature data. The easiest way in Python is using the Flask framework backed with a Mongo DB. Watch this space for….

Building a RESTful web service using Pythong & Flask

 

Changing the hostname on a Raspberry Pi

Changing your hostname on a Raspi is pretty straight forward,

To get a host name use

keith@fuzepi ~ $ hostname
fuzepi

We now need to change the host name for the local address 127.0.0.1

keith@fuzepi ~ $ sudo vi /etc/hosts
[sudo] password for keith:

Change the name associated with 127.0.01, then we need to change the actual name of the host

keith@fuzepi ~ $ sudo nano /etc/hostname

Change the name in this file and save
One more step is to update the system

keith@fuzepi ~ $ sudo /etc/init.d/hostname.sh

Finally, reboot the Pi

keith@fuzepi ~ $ reboot

and the new name should be available with the command ‘hostname’

keith@gertpi ~ $ hostname
gertpi

Running GGTS on OSX under Java 7

I had a look at this and it looks to be a bug somehow related to the way that RJB on OSX works. RJB is the library that Buildr uses to interact with the JVM. Essentially RJB does not seem to allow the configuration of the JVM without setting some environment variables (possibly at build time?). Seehttp://rjb.rubyforge.org/.

There are two main ways to work around this;

  • use the external compiler by adding something like “compile.using(:externaljavac)” into your buildfile.
  • use JRuby.

I will look into what is required to solve this correctly for the next release (1.4.8).

Update

Fixed in 1.4.8 – a work around for 1.4.7 is to set the JVM_LIB environment variable like

export JVM_LIB=$JAVA_HOME/jre/lib/server/libjvm.dylib

Install Python 3 Raspberry Pi

Its pretty simple to get Python 3.2 ( the latest for Pi ) installed, just a couple of apt-get commands and a little shell hacking will do it

First lets get Python 3 install

sudo apt-get install python3

Next get setup tools

sudo apt-get install python3-setuptools

And finally we want Pip installing but ensuring it works for Python 3

sudo apt-get install python3-pip

Then modify you shell script to alias ‘python’ to run ‘python3’

alias vi='vim'
alias python='python3.2'
alias pip='pip-3.2'

The best way to do this is with your favourite editor and then adding the lines you mention, followed by using source to make them available in your current session.

sudo nano ~/.bash_aliases
source ~/.bash_aliases

Jobs a good’un !