A few days ago I thougth I’d take a look at calling C functions from haskell. I wrote up the following set of files:
foo.h:
int foo(int i);
foo.c:
int
foo(int i)
{
return i * i;
}
Foo.hs:
module Main where
import Foreign.C.Types
main = do
r <- foo 2
putStrLn $ show r
foreign import ccall safe "foo.h foo" foo :: CInt -> IO CInt
Compiling the C file was of course no problem:
% gcc -c foo.c
The haskell file offered some resistance:
% ghc -c Foo.hs
Foo.hs:9:8: parse error on input `import'
It took me a round on haskell-cafe before I found out that ghc needs to be told to use the foreign function interface, -ffi or -fffi:
% ghc -c -fffi Foo.hs
Linking is a snap after that:
% ghc -o foo foo.o Foo.o
% ./foo
4
It’s also possible to build and link it all in one go:
% ghc --make -fffi -o foo foo.c Foo.hs
Now, that’s pretty nice, however it’d be even nicer to use cabal to do the building. At the same time I decided to put c2hs to use. It seemed to be a lot easier than having to create the import statements manually. I ended up with the following:
csrc/foo.h:
#ifndef _FOO_H_
int foo(int);
#endif
csrc/foo.c:
#include "foo.h"
int
foo(int i)
{
return i * i;
}
I couldn’t get cabal to accept Foo.chs as the file containing the Main module in my project. So I ended up putting all the relevant code in Foo and then have a dummy Main.
src/Foo.chs:
module Foo where
#include "foo.h"
import Foreign.C.Types
main = do
r <- {# call foo #} 2
putStrLn $ show r
Here’s the dummy Main.
src/Main.hs:
module Main where
import qualified Foo
main = Foo.main
The cabal file is rather straight forward. It took me a round on haskell-cafe to find out how to let the compiler know that I need the foreign function interface without putting compiler directives in the source file.
As I promised earlier here’s a post on my playing with files and directories in Haskell. This was a few days ago so I’ve forgotten a few of the twists and turns that took me to the goal. Forgive me for that.
First, my goal was to list all files below a directory, recursively. I was sort of hoping to find something similar to Python’s os.walk(). No such luck!
I found out a few things.
getDirectoryContents returns everything in a directory, including . and ... I needed a filter to remove them:
isDODD f = not $ (endswith "/." f) || (endswith "/.." f)
(At first I called it isDotOrDotDot but I like isDODD better.)
I also needed to separate out the directories and files from the result of getDirectoryContents:
getDirectoryContents returns a list of the contents in the directory you point it to. All file names/directory names are relative to that path. That means the next thing I needed was to join paths. I first couldn’t believe that there wasn’t a function to do that. I mean, I can list contents of a directory, I can find out if something’s a file or a directory, but the most basic manipulation of paths isn’t there. At first I simply concatenated strings, but I didn’t worry about making it cross platform or anything. Then I found that Cabal comes with libraries that handles cross-platform issues properly, but that library was “closed”. After moaning asking on haskell-cafe I found FilePath. It’s even packaged for Debian here.
FilePath.joinPath takes a list of strings to join, while I was only interested in joining two strings at a time:
joinFN p1 p2 = joinPath [p1, p2]
Putting it all together I ended up with the following:
As you can see I did spend some time thinking about Monads lately. Something that’s especially pressing if one wants to do IO in Haskell since the IO Monad can’t be escaped from. Next catFile (which based on the use above should have the type FilePath -> IO [String]). I did some experimenting and searching in Hoogle among the System.IO functions. I found openFile, hGetContents that would let me open and read the file. I played a bit with that:
That doesn’t have quite the required type, but that isn’t the only problem. The combination of hGetContents and hClose doesn’t quite work—the file is never read (laziness in action!). I removed the hClose (since the process isn’t very long-lived that doesn’t bother me so much) and I added a lines:
I guess it’s time to explain the reason for returning IO [String] rather than IO String. The latter would have simplified both catFile and main. What I really wanted was to make each line of a file an item in a set. My first thought was to fold it:
Then I reversed my thinking and tried to lift the function into the monad instead:
liftM Set.fromList $ catFile "test_file"
At that point I felt I had somewhat exhausted this particular little playground and went on to listing files and directories, but that’s a story for another post.
Yesterday I decided to leave the relative safety of solving exercises in tutorials and instead try solving a small problem I had at work. I had pairs of times (points in time, like Wednesday November 8 01:17) and I needed the difference between them. Not a tricky problem by any stretch of the imagination, but I figured I had to start using Haskell at some point. I might as well make this that point.
I started out by playing around with System.Time and System.Locale in gchi. One thing that seemed missing was a function that took a String and tried to interpret it as a CalendarTime. After a mail to Haskell Cafe I discovered MissingH.
I found myself programming top-down, stubbing “sub functions” while trying to get the types of the current function right. It turns out I was “lucky” and there wasn’t many monads involved, but still I did run into some problems with mixing do notation and let, where, and case. In the end I split out those constructs and kept only the most basic syntactical constructs inside the do.
Here’s the end result, not the most functional piece of Haskell code ever seen, but it’s the first time I dip my toes in the sea of Haskell without a tutorial life-west.
module Main where
import System.Locale
import System.Time
import System.Environment
import MissingH.Time.ParseDate
diffAndToString :: CalendarTime -> CalendarTime -> String
diffAndToString s e =
let
sC = toClockTime s
eC = toClockTime e
diff = normalizeTimeDiff $ diffClockTimes eC sC
in
formatTimeDiff defaultTimeLocale "%R" diff
calcDiff :: String -> String -> Either String String
calcDiff start end =
let
-- I had problems using %Y, so I'm using %C%y instead
sT = parseCalendarTime defaultTimeLocale "%C%y%m%d-%H%M" start
eT = parseCalendarTime defaultTimeLocale "%C%y%m%d-%H%M" end
in
case (sT, eT) of
(Nothing, _) -> Left "start time"
(_, Nothing) -> Left "end time"
(Just s, Just e) -> Right $ diffAndToString s e
resultString :: String -> String -> String
resultString s e =
let
calculatedDiff = calcDiff s e
in
case calculatedDiff of
(Left s) -> "Bad " ++ s
(Right s) -> s
main :: IO ()
main = do
args <- getArgs
putStrLn $ resultString (args !! 0) (args !! 1)