Pointer manipulations in Haskell
Some situations demand working with memory ponters. This may be the case when you are interfacing to anexternal library or working with disk data structures. Fortunately, Haskell provides the control you need to work wth pointers. This is a small example of how you can manage memory allocation and using it store priitive types.
We import the Foreign module.
>import Foreign
This allocates a byte buffer. Word8 is Haskell's primitive type for an octet. aAllocByteBuf allocates a byte buffer of specified size. The last part of the type signature of the method can be changed if you wanted to work with some other primitive type.
>allocByteBuf :: Int -> IO (Ptr Word8)
>allocByteBuf n
> = do buf <- mallocArray n
> return buf
putInt stores an integer in the buffer at specified offset. Note that the buffer we are working with is a byte buffer and castPtr cast it to the appropriate type. Unlike the cast operator in C, there is no type specified here. That information comes from the type of the value being stored and Haskell's type inference dedecues the type to cast to.
pokeElemOff stores the integer in the buffer at specified offset. If the architecture has any alignment requirements, the offset should honor that or you will get an error.
>putInt :: Ptr Word8 -> Int -> Int -> IO ()
>putInt buf offset i
> = do pokeElemOff (castPtr buf) offset i
> return ()
getInt is similar to putInt. Again, the type signature and castPtr work together to retrieve the integer value from the buffer.
>getInt :: Ptr Word8 -> Int -> IO Int
>getInt buf offset
> = do i <- peekElemOff (castPtr buf) offset
> return i
Here we exercise the functions above. Note the type signature attached to 255. Haskell can't dedeuce the type in all cases and requires you to disambiguate the type.
>main = do
> buf <- allocByteBuf 1024
> putInt buf 0 (255::Int)
> i <- getInt buf 0
> putStrLn $ "i: " ++ show i
> free buf
It is not clear if there a way to avoid writing get/put functions for each primitive type. Comments?
Sunday, February 22, 2009
Friday, January 30, 2009
xmonad Stops Responding to Keyboard Input
I have been using xmonad on Ubuntu Hardy and extremely happy with its model. When compared to my previous window manager stumpwm, it is missing a few niceties but more than makes up for those with its flexible layout management. But I nearly gave up on xmonad when I started running into an issue which is a real deal breaker.
The problem is this: everything is fine and dandy and for no apparent reason, xmonad stops responding to keyboard. The current window, however, accepts the keyboard input. My only workaround was to restart my session. Completely unacceptable.
Googling for "xmonad stops responding" brought up this bug report http://code.google.com/p/xmonad/issues/detail?id=97. Comment number 26 clued me in to what might be happening. Some more googling and I chanced upon this http://markmail.org/message/4gmek2d5pxv76dlw#query:xmonad%20xmobar%20dynamiclog+page:1+mid:rnmlvyyft33gnjpm+state:results, Andrea Rossato's last entry on that thread gives you the solution which is to run the StdinReader in xmobar's configuration.
Finally, I understand what is happening. xmonad is writing to stdout and xmobar to which the xmonad's output is being piped, must read it or xmonad will block when the pipe fills up. The problem is with xmobar configuration below.
I have been using xmonad on Ubuntu Hardy and extremely happy with its model. When compared to my previous window manager stumpwm, it is missing a few niceties but more than makes up for those with its flexible layout management. But I nearly gave up on xmonad when I started running into an issue which is a real deal breaker.
The problem is this: everything is fine and dandy and for no apparent reason, xmonad stops responding to keyboard. The current window, however, accepts the keyboard input. My only workaround was to restart my session. Completely unacceptable.
Googling for "xmonad stops responding" brought up this bug report http://code.google.com/p/xmonad/issues/detail?id=97. Comment number 26 clued me in to what might be happening. Some more googling and I chanced upon this http://markmail.org/message/4gmek2d5pxv76dlw#query:xmonad%20xmobar%20dynamiclog+page:1+mid:rnmlvyyft33gnjpm+state:results, Andrea Rossato's last entry on that thread gives you the solution which is to run the StdinReader in xmobar's configuration.
Finally, I understand what is happening. xmonad is writing to stdout and xmobar to which the xmonad's output is being piped, must read it or xmonad will block when the pipe fills up. The problem is with xmobar configuration below.
Config { font = "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*"The "Run StdinReader" line is the key to fixing this problem. I think it is optional to add %StdinReader% to the template.
, bgColor = "black"
, fgColor = "grey"
, position = Top
, commands = [ Run Weather "KSQL" ["-t",": F/ C","-L","18","-H","80","--normal","green","--high","red","--low","lightblue"] 36000
, Run Network "eth0" ["-L","0","-H","32","--normal","green","--high","red"] 10
, Run Network "eth1" ["-L","0","-H","32","--normal","green","--high","red"] 10
, Run Cpu ["-L","3","-H","50","--normal","green","--high","red"] 10
, Run Memory ["-t","Mem:%"] 10
, Run Swap [] 10
, Run Com "uname" ["-s","-r"] "" 36000
, Run Date "%a %b %_d %Y %H:%M:%S" "date" 10
, Run StdinReader
]
, sepChar = "%"
, alignSep = "}{"
, template = "%cpu% | %memory% * %swap% | %eth0% - %eth1% }{%date% | %KSQL% %StdinReader%"
}
Thursday, January 08, 2009
Haskell XML Processing Using HXT
There seem to be two ways to process XML in Haskell -- HaXmL and HXT. HXT seems to be the most capable and understands XML namespaces. Support for namespaces being key for my needs, I started with HXT. As it happens often, I ran into some issues and spent more than a few hours trying to understand them.
Here is a simple HXT program to parse an XML document and write it to the terminal. The XML document is embedded in the code. It works as expected.
There seem to be two ways to process XML in Haskell -- HaXmL and HXT. HXT seems to be the most capable and understands XML namespaces. Support for namespaces being key for my needs, I started with HXT. As it happens often, I ran into some issues and spent more than a few hours trying to understand them.
Here is a simple HXT program to parse an XML document and write it to the terminal. The XML document is embedded in the code. It works as expected.
--{-# LANGUAGE Arrows, NoMonomorphismRestriction #-} --{-# OPTIONS -fglasgow-exts -cpp #-} import System.Environment import System.IO import Text.XML.HXT.Arrow main :: IO () main = do runX ( readString [(a_validate, v_0) , (a_encoding, isoLatin1)] "<a><b/><b/></a>" >>> writeDocument [] "/dev/tty" ) return ()Okay, that works beautifully. I will now add filter to select only XML elements from the document.
--{-# LANGUAGE Arrows, NoMonomorphismRestriction #-} --{-# OPTIONS -fglasgow-exts -cpp #-} import System.Environment import System.IO import Text.XML.HXT.Arrow main :: IO () main = do runX ( readString [(a_validate, v_0) , (a_encoding, isoLatin1)] "<a><b/><b/></a>" >>> deep isElem >>> writeDocument [] "/dev/tty" ) return ()That produces the entire document. Say, I am interested in extracting all elements named b, and I will enhance my filter.
--{-# LANGUAGE Arrows, NoMonomorphismRestriction #-} --{-# OPTIONS -fglasgow-exts -cpp #-} import System.Environment import System.IO import Text.XML.HXT.Arrow main :: IO () main = do runX ( readString [(a_validate, v_0) , (a_encoding, isoLatin1)] "<a><b/><b/></a>" >>> deep (isElem >>> hasName "a") >>> writeDocument [] "/dev/tty" ) return ()
This is where my productivity came to a screeching halt. I started suspecting that somehow, my filter wasn't specified right, HXT has a silly bug and so on.
After significant frustration, I started reading HXT tutorial. Turns out that readDocument returns a Rose Tree and write document expects to receive a similar tree. Once I added
the hasName filter, the result of the arrow no longer returned something that was acceptable to writeDocument. These filter functions, silently ignore errors. Phew! The fix is,
adding root element to the result of filter.
--{-# LANGUAGE Arrows, NoMonomorphismRestriction #-} --{-# OPTIONS -fglasgow-exts -cpp #-} import System.Environment import System.IO import Text.XML.HXT.Arrow main :: IO () main = do runX ( readString [(a_validate, v_0) , (a_encoding, isoLatin1)] "<a><b/><b/></a>" >>> root [] [deep (isElem >>> hasName "b")] >>> writeDocument [] "/dev/tty" ) return ()
HXT tutorial shows a canonical way to write HXT code and I should probably switch to that style for serious work,
Hope this serves as a reminder to rtfm next time around!
Saturday, August 23, 2008
Writing a COM client in Haskell
This is most likely GHC specific. I am currently using GHC 6.8.3 and any other version may not work.
It should be obvious that we need FFI to make C calls to Windows COM components. I also use Krasimir Angelov's hscom package. Hscom implements the machinery needed to work with COM components.
It should be noted here that another subtle requirement is GHC extensions needed to make this all work. I had a tough time getting around a compilation problem. Krasimir, who is the author of hscom, graciously helped me with that problem. You can read the exact issue at http://www.nabble.com/Unboxing-VT_VARIANT-in-hscom-td19044443.html#a19044443. The short summary is that you need to enable GHC extensions with the switch -fglasgow-exts .
GHC package names seem to have changed over time. I spent a few hours chasing why import Process was failing. Well, it is now import System.Process.
In my next blog, I will show a minimal COM client written in Haskell.
This is most likely GHC specific. I am currently using GHC 6.8.3 and any other version may not work.
It should be obvious that we need FFI to make C calls to Windows COM components. I also use Krasimir Angelov's hscom package. Hscom implements the machinery needed to work with COM components.
It should be noted here that another subtle requirement is GHC extensions needed to make this all work. I had a tough time getting around a compilation problem. Krasimir, who is the author of hscom, graciously helped me with that problem. You can read the exact issue at http://www.nabble.com/Unboxing-VT_VARIANT-in-hscom-td19044443.html#a19044443. The short summary is that you need to enable GHC extensions with the switch -fglasgow-exts .
GHC package names seem to have changed over time. I spent a few hours chasing why import Process was failing. Well, it is now import System.Process.
In my next blog, I will show a minimal COM client written in Haskell.
Getting started with Haskell
Installation
As you can see on haskell.org, there are four implementations of Haskell. I am using GHC. Installation on MS Windows presents no serious issues (unfortunately, many fine things are Linux only with Windows implementation either non-existent or a step child like effort. I am glad GHC team seems to consider Windows effort important enough.
Packages
Packages are at http://hackage.haskell.org/packages/archive/pkg-list.html. I haven't managed to get it working on my system yet. Installing packages one at a time has worked out okay. Here is a sample of how I do it.
Issues
It is possible you will run into some issues in building. For e.g., hscom package complains of missing files as below.
I got around that by copying the missing file.
Installing packages usually only takes a few steps but getting cabal to work would be much better (presuming that it takes care all dependencies of the package I am trying to install).
Installation
As you can see on haskell.org, there are four implementations of Haskell. I am using GHC. Installation on MS Windows presents no serious issues (unfortunately, many fine things are Linux only with Windows implementation either non-existent or a step child like effort. I am glad GHC team seems to consider Windows effort important enough.
Packages
Packages are at http://hackage.haskell.org/packages/archive/pkg-list.html. I haven't managed to get it working on my system yet. Installing packages one at a time has worked out okay. Here is a sample of how I do it.
- Download the package or use darcs client to check out the sources
- cd to the directory which contains Setup.hs or Setup.lhs
- Run: ghc --make Setup.hs
- Run: setup configure
- Run: setup build
- Run: setup install
Issues
It is possible you will run into some issues in building. For e.g., hscom package complains of missing files as below.
C:\tools\haskell\hscom>setup makefile
Preprocessing library hscom-0.1...
Generating Makefile hscom-0.1...
C:\tools\haskell\hscom>setup configure
Configuring hscom-0.1...
Warning: No license-file field.
C:\tools\haskell\hscom>dir dis
C:\tools\haskell\hscom>setup build
Preprocessing library hscom-0.1...
Building hscom-0.1...
src\Foreign\COM\Automation\SafeArray.hsc:22:22:
Can't find dist\build/Foreign/COM/Automation/Variant.hs-boot
I got around that by copying the missing file.
C:\tools\haskell\hscom>copy src\Foreign\COM\Automation\Variant.hs-boot dist\buil
d\Foreign\COM\Automation
1 file(s) copied.
C:\tools\haskell\hscom>setup configure
C:\tools\haskell\hscom>setup build
Preprocessing library hscom-0.1...
Building hscom-0.1...
[ 1 of 17] Compiling Foreign.COM.Automation.Variant[boot] ( dist\build/Foreign/C
OM/Automation/Variant.hs-boot, dist\build/Foreign/COM/Automation/Variant.o-boot
)
[ 2 of 17] Compiling Foreign.COM.Automation.BSTR ( src/Foreign/COM/Automation/BS
TR.hs, dist\build/Foreign/COM/Automation/BSTR.o )
[ 3 of 17] Compiling Foreign.COM.Marshal.Alloc ( src/Foreign/COM/Marshal/Alloc.h
s, dist\build/Foreign/COM/Marshal/Alloc.o )
[ 4 of 17] Compiling Foreign.COM.Marshal.Exception ( dist\build/Foreign/COM/Mars
hal/Exception.hs, dist\build/Foreign/COM/Marshal/Exception.o )
[ 5 of 17] Compiling Foreign.COM.Automation.Currency ( dist\build/Foreign/COM/Au
tomation/Currency.hs, dist\build/Foreign/COM/Automation/Currency.o )
[ 6 of 17] Compiling Foreign.COM.Automation.Decimal ( dist\build/Foreign/COM/Aut
omation/Decimal.hs, dist\build/Foreign/COM/Automation/Decimal.o )
[ 7 of 17] Compiling Foreign.COM.Automation.SafeArray ( dist\build/Foreign/COM/A
utomation/SafeArray.hs, dist\build/Foreign/COM/Automation/SafeArray.o )
[ 8 of 17] Compiling Foreign.COM.Registry ( dist\build/Foreign/COM/Registry.hs,
dist\build/Foreign/COM/Registry.o )
C:\DOCUME~1\pprakash\LOCALS~1\Temp\ghc2832_0\ghc2832_0.hc: In function `s78n_ent
ry':
C:\DOCUME~1\pprakash\LOCALS~1\Temp\ghc2832_0\ghc2832_0.hc:156: warning: implicit
declaration of function `com_hresult_from_win32'
[ 9 of 17] Compiling Foreign.COM.Marshal.VTable ( src/Foreign/COM/Marshal/VTable
.hs, dist\build/Foreign/COM/Marshal/VTable.o )
[10 of 17] Compiling Foreign.COM.Marshal ( src/Foreign/COM/Marshal.hs, dist\buil
d/Foreign/COM/Marshal.o )
[11 of 17] Compiling Foreign.COM.GUID ( src/Foreign/COM/GUID.hs, dist\build/Fore
ign/COM/GUID.o )
[12 of 17] Compiling Foreign.COM.Client ( dist\build/Foreign/COM/Client.hs, dist
\build/Foreign/COM/Client.o )
[13 of 17] Compiling Foreign.COM.Server ( src/Foreign/COM/Server.hs, dist\build/
Foreign/COM/Server.o )
[14 of 17] Compiling Foreign.COM.Automation.IDispatch ( dist\build/Foreign/COM/A
utomation/IDispatch.hs, dist\build/Foreign/COM/Automation/IDispatch.o )
[15 of 17] Compiling Foreign.COM.Automation.Variant ( dist\build/Foreign/COM/Aut
omation/Variant.hs, dist\build/Foreign/COM/Automation/Variant.o )
[16 of 17] Compiling Foreign.COM.Automation ( src/Foreign/COM/Automation.hs, dis
t\build/Foreign/COM/Automation.o )
[17 of 17] Compiling Foreign.COM.ConnectionPoint ( dist\build/Foreign/COM/Connec
tionPoint.hs, dist\build/Foreign/COM/ConnectionPoint.o )
/usr/bin/ar: creating dist\build\libHShscom-0.1.a
C:\tools\haskell\hscom>setup install
Installing: C:\Program Files\Haskell\hscom-0.1\ghc-6.8.3
Registering hscom-0.1...
Reading package info from "dist\\installed-pkg-config" ... done.
Saving old package config file... done.
Writing new package config file... done.
Installing packages usually only takes a few steps but getting cabal to work would be much better (presuming that it takes care all dependencies of the package I am trying to install).
Learning Haskell Redux
When you are looking for a nice language that doesn't suck, which would inevitably rule out the languages most of us use at work, there are many choices. Usually, I am torn between Lisp, Erlang and Haskell. I have become quite comfortable with Lisp but Erlang and Haskell still present a high starting effort.
So, I started toying with another language JRuby. Unfortunately, the issue of FFI in JRuby is still a challenge and JRuby still has a few rough edges. After a few attempts at using it, I gave up and decided to try Haskell instead. One of my requirements was to be able to implement COM client programming and Haskell turned out to be not such a challenge after all. I will blog more on my COM client in Haskell later.
Picking up Haskell after a couple of years has been interesting. Much to my surprise, my understanding of Haskell has improved a lot. Interestingly, Lisp proved to be quite a challenge in the beginning but at some point, it became quite natural. The best way I can describe that is that the parenthesis seemed to disappear and suddenly everything became very clear. I am having a similar experience with Haskell at the moment. Suddenly, I really understand the benefits of monadic style of programming. The understanding has progressed beyond that is gained by reading what others have written.
Speaking of other's work, I discovered a new Haskell book in progress, http://book.realworldhaskell.org/. The few chapters I have read have been very useful. I am glad to a book which makes this wonderful language more accessible.
Haskell is a complex language and a real mind bender. However, a pragmatic approach to learning it is likely to be an easier course for most people. Hopefully, I will be able to blog as I go along and end up with something worth reading.
When you are looking for a nice language that doesn't suck, which would inevitably rule out the languages most of us use at work, there are many choices. Usually, I am torn between Lisp, Erlang and Haskell. I have become quite comfortable with Lisp but Erlang and Haskell still present a high starting effort.
So, I started toying with another language JRuby. Unfortunately, the issue of FFI in JRuby is still a challenge and JRuby still has a few rough edges. After a few attempts at using it, I gave up and decided to try Haskell instead. One of my requirements was to be able to implement COM client programming and Haskell turned out to be not such a challenge after all. I will blog more on my COM client in Haskell later.
Picking up Haskell after a couple of years has been interesting. Much to my surprise, my understanding of Haskell has improved a lot. Interestingly, Lisp proved to be quite a challenge in the beginning but at some point, it became quite natural. The best way I can describe that is that the parenthesis seemed to disappear and suddenly everything became very clear. I am having a similar experience with Haskell at the moment. Suddenly, I really understand the benefits of monadic style of programming. The understanding has progressed beyond that is gained by reading what others have written.
Speaking of other's work, I discovered a new Haskell book in progress, http://book.realworldhaskell.org/. The few chapters I have read have been very useful. I am glad to a book which makes this wonderful language more accessible.
Haskell is a complex language and a real mind bender. However, a pragmatic approach to learning it is likely to be an easier course for most people. Hopefully, I will be able to blog as I go along and end up with something worth reading.
Friday, May 12, 2006
Wednesday, May 10, 2006
Here is a toy evaluator of integer expressions:
module Main where
data Expr = Const Int | Add Expr Expr | Sub Expr Expr | Mul Expr Expr | Div Expr Expr
main = print (eval (Div (Const 20) (Add (Const 1) (Sub (Const 10) (Const 2)))))
eval :: Expr -> Int
eval (Const k) = k
eval (Add x y) = eval x + eval y
eval (Sub x y) = eval x - eval y
eval (Mul x y) = eval x * eval y
eval (Div x y) = eval x `div` eval y
Tuesday, May 09, 2006
Subscribe to:
Posts (Atom)