
Hello again, I'm still working on that binding, and I've come to a problem that I just can't figure out. I'm sure it's staring me right in the face, so I think another pair of eyes to take a look. So if you look at my previous message, I defined a linked list data type in C. I'm trying to convert it to a Haskell list of strings, so here's my function: linkedListToHaskellStringList :: LinkedList -> IO [String] linkedListToHaskellStringList listPtr = let convertList' ptr = if listIsNull ptr then [] else let str = peekCString =<< (linked_list_getdata ptr) next <- linked_list_next ptr str : (convertList' next) in sequence $ convertList' listPtr listIsNull :: LinkedList -> Bool listIsNull (LinkedList ptr) = ptr == nullPtr So here's the compile error: Option.hsc:63:14: Couldn't match expected type `[t]' against inferred type `IO LinkedList' In a 'do' expression: next <- linked_list_next ptr In the expression: if listIsNull ptr then [] else do let str = peekCString =<< linked_list_getdata ptr next <- linked_list_next ptr str : (convertList' next) In the definition of `convertList'': convertList' ptr = if listIsNull ptr then [] else do let str = ... next <- linked_list_next ptr str : (convertList' next) Could anyone tell me what I'm doing wrong? Thanks a lot! -Rob

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
linkedListToHaskellStringList :: LinkedList -> IO [String] linkedListToHaskellStringList listPtr = let convertList' ptr = convertList' :: LinkedList -> [IO String], I infer? if listIsNull ptr then [] else are you doing IO here or not? You need a 'do' if you are (else this is a syntax error), but IO /= [], so what is the function returning? let str = peekCString =<< (linked_list_getdata ptr) next <- linked_list_next ptr str : (convertList' next) in sequence $ convertList' listPtr
listIsNull :: LinkedList -> Bool listIsNull (LinkedList ptr) = ptr == nullPtr
I'd recommend recursion without the 'sequence', I think, so you can do IO along the way - traversing the LinkedList - and then 'return' the list made from (:). (and throw in unsafeInterleaveIO if you're feeling sadistical and want parts of the traversal to be performed at unspecified later dates) Isaac -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFGTNvrHgcxvIWYTTURAr9NAKDEwWAtae3OfVf8I/Aqgwnuq4g9LgCgvu0F FTB0hdr7tYaf/6PElVNY+6Y= =EtHd -----END PGP SIGNATURE-----

Isaac Dupree
linkedListToHaskellStringList :: LinkedList -> IO [String] linkedListToHaskellStringList listPtr = let convertList' ptr = convertList' :: LinkedList -> [IO String], I infer?
Correct.
if listIsNull ptr then [] else
are you doing IO here or not? You need a 'do' if you are (else this is a syntax error), but IO /= [], so what is the function returning? My mistake; I left off the 'do.' My original code does have it, though.
I figure since the null case returns [] (which should be a valid [IO String], and str is an IO String, it should work. In fact, if I take out the next <- ... line and substitute ptr for next, it compiles. But that's not exactly desirable behavior...=P
let str = peekCString =<< (linked_list_getdata ptr) next <- linked_list_next ptr str : (convertList' next) in sequence $ convertList' listPtr
listIsNull :: LinkedList -> Bool listIsNull (LinkedList ptr) = ptr == nullPtr
I'd recommend recursion without the 'sequence', I think, so you can do IO along the way - traversing the LinkedList - and then 'return' the list made from (:). (and throw in unsafeInterleaveIO if you're feeling sadistical and want parts of the traversal to be performed at unspecified later dates)
The problem I have with that is that I'd have to do something like this: str <- peekCString =<< (linked_list_getdata ptr) next <- linked_list_next ptr rest <- linkedListToHaskellStringList next return (str : rest) I don't like this because it's not really tail recursive. I've been told tail recursion is overrated, but since I don't really know how long the C linked lists are going to be (could be 10 elements, could be 100), I don't think avoiding a stack overflow is overrated. Thanks, Rob

Rob Hoelz wrote:
The problem I have with that is that I'd have to do something like this:
str <- peekCString =<< (linked_list_getdata ptr) next <- linked_list_next ptr rest <- linkedListToHaskellStringList next return (str : rest) Exactly! That's normal Haskell code!
I don't like this because it's not really tail recursive. I've been told tail recursion is overrated, but since I don't really know how long the C linked lists are going to be (could be 10 elements, could be 100), I don't think avoiding a stack overflow is overrated.
If you're worried about stack overflows, make a million element list and try your Haskell code on it (with optimizations if applicable). See if it actually stack overflows. Hugs is relatively bad, GHC usually doesn't stack overflow but it has happened to me (once). refactoring:
str <- peekCString =<< (linked_list_getdata ptr) rest <- linkedListToHaskellStringList =<< linked_list_next ptr return (str : rest)
further:
liftM2 (:) (peekCString =<< (linked_list_getdata ptr) (linkedListToHaskellStringList =<< linked_list_next ptr) (import Control.Monad if necessary for liftM2)
Okay, does that look weird enough for you? Isaac

Isaac Dupree
Isaac Dupree wrote:
liftM2 (:) (peekCString =<< (linked_list_getdata ptr)) (linkedListToHaskellStringList =<< linked_list_next ptr)
formerly missing parenthesis fixed in the above before it bites you :(
Isaac
Thanks for the help, Isaac. I didn't know how good of a job GHC did when optimizing code like that. I don't have a problem with that code I wrote as a rule (it doesn't look ugly to me), but I just wanted to make sure my binding didn't cause crashes. I like the liftM2 thing, though; I think I'll go with that. Thanks, Rob
participants (2)
-
Isaac Dupree
-
Rob Hoelz