Monday, January 21, 2013

Haskell Tidbits

Working source code for using various Haskell packages (MySQL, Curl, etc.)

Full Source Code For All Examples

Source Tree: http://devrand.org:8080/cgi-bin/cgit/haskellTidbits/tree/
Snapshots: http://devrand.org:8080/cgi-bin/cgit/haskellTidbits/commit/
Git Access: git clone http://devrand.org:8080/git/haskellTidbits

Arduino Serial IO

Overview

The Arduino is a popular electronics prototyping platform. It is easy to interface to a computer via a real or emulated (Through USB) serial connection. This write-up details how to communicate with the Arduino in Haskell.

Pre-requisites

  • Arduino software installed and working.
  • Haskell Platform installed with Serial package from Hackage(cabal install serial)
  • A program with serial I/O loaded on the Arduino (The PhysicalPixel example that comes with arduino will work)

Send a simple command

import System.Serial
import IO

serialCommand :: String -> IO ()
serialCommand comm = do 
  h <- font="font"> openSerial "/dev/ttyUSB0" B9600 8 One NoParity Software
  hPutStr h comm

For example running serialCommand "H" in ghci, would turn on the LED from the PhysicalPixel example. h is a normal file handle so I/O can be performed in the same way.

Servo and LED Demo

Quick demo of running a servo motor and LED from Haskell using serialMonitor.hs. H turns on the light, L turns it off, the numbers 0-9 are the step to take (0-180) by 20 degree increments. The Arduino sends back a status after each command, saying either the state of the light, or the degree of the servo.
Video of serialMonitor.hs program running:



HDBC MySQL Connectivity

Overview

HDBC-mysql is a way to talk to mysql using Haskell. Like alot of things in Hackage, there isn't alot of demo code, so here is how I've been using it. Besides the initial connection it provides the same functions/types as the rest of HDBC.

Database Setup

Requires the following MySQL setup:

CREATE DATABASE hdbcTest;
GRANT ALL ON hdbcTest.* TO hdbc@'%' IDENTIFIED BY 'hdbc';
use hdbcTest;
create table test ( 
   id INT NOT NULL AUTO_INCREMENT, 
   PRIMARY KEY(id), 
   value varchar(255)
);
Assumes the local socket file is at (Specified in mySQL's my.cnf file):
  /var/run/mysqld/mysqld.sock
Change as needed.

Haskell Connection

Simple connection and test:
import Control.Monad
import Database.HDBC
import Database.HDBC.MySQL

main = do
   conn <- font="font"> connectMySQL defaultMySQLConnectInfo {
    mysqlHost       = "localhost",

    mysqlPort       = 3306,
    mysqlUnixSocket = "/var/run/mysqld/mysqld.sock",
    mysqlDatabase   = "hdbcTest",

    mysqlUser       = "hdbc",
    mysqlPassword   = "hdbc"
   }
   rows <- font="font"> quickQuery' conn "SELECT 1 + 1" []
   forM_ rows $ row -> putStrLn $ show row

Should return: [SqlInteger 2] Something a little more complicated. Grab the count of entries, insert that count, and then spit out all the values. After the connection is established (ie the bottom of the last example).
   rows <- font="font"> quickQuery' conn "SELECT count(*) from test" []
   run conn ("insert into test (value) values" ++

             countString rows) []
   rows <- font="font"> quickQuery' conn "SELECT value from test" []
   forM_ rows $ row -> putStrLn $ sqlValue row

You should get entries of the form: "Count "#""
That increase each time the code is ran.

Collatz Conjecture

Overview

The Collatz Conjecture is based on sequences from the following formulas:
n/2 for even n
3*n + 1 for odd n
These seequences go back down to one, no matter what starting number is chosen. The interesting part is that noone has been able to formally prove this. So I started writing some simple code to play around with it, and practice my Haskell coding.

Collatz Sequence Code

Code to generate sequences and find the lengths of the sequences:
test :: Int -> Int

test x | even x     = x `div` 2
       | otherwise  = 3*x + 1

collatz :: Int -> [Int]
collatz 1 = [1]

collatz x = x : collatz (test x)

numCollatz = map (length . collatz) [1..]

Output Code

Generates a table that gnuplot can handle.
format x y = show x ++ "t" ++ show y

table x = unlines (zipWith format [1..] (take x numCollatz))

main = writeFile "collatz.dat" (table 100000)

Media


     


XOR Character Arrays

Overview

Just what it sounds like, take 2 strings "abcd" and "efgh" and XOR them together to get a new string. There are custom libraries available, but nothing that's default in Hugs or GHC that I know of. It's a simple one liner, but not particularly intuitive ( Like anything in Haskell is :P )

Code

Interpreter session:
:module +Data.ByteString.Internal
:module +Data.Bits
let xorStrs x y = map w2c (zipWith xor (map c2w x) (map c2w y))
let c1 = "Test String"
let c2 = "Hello World"
xorStrs c1 c2

Non Prelude Functions

  • c2w -- Character2Word changes an individual Char to a Word8 type
  • w2c -- Reverse of c2w, converts a Word8 to a Char
  • xor -- Only works on Word# types, does a bitwise or on 2 values

No comments: