3

This is a follow up question to this. I'm using a graphic library in Haskell called Threepenny-GUI. In this library the main function returns a UI monad object. I'm trying to execute a simple print command with no success. What is a right work around to enable printing for debugging purposes.

Code:

main :: IO ()
main = startGUI defaultConfig setup

setup :: Window -> UI ()
setup w = do

print "debug message 1 "

Error:

Couldn't match type ‘IO’ with ‘UI’
Expected type: UI ()
  Actual type: IO ()
In a stmt of a 'do' block: print "labels and values "
Community
  • 1
  • 1
vondip
  • 13,809
  • 27
  • 100
  • 156
  • Your `do` block must contain only one monad (ie either `UI` or `IO` but not both). If you want to debug in Haskell, a debugger might be useful. – Alec Jun 22 '15 at 19:52
  • How do I support print then? – vondip Jun 22 '15 at 19:58
  • 1
    You should try to preserve the formatting of your Haskell code in your code blocks. The code in your question has a parse error because there are no spaces before `print`. One thing that helps is StackOverflow shortcut Ctrl-k. If you highlight a block of text in a question or answer and hit Ctrl-k, it will indent each line by 4 spaces. As far as I know, this shortcut isn't officially documented anywhere but it's handy. – David Young Jun 22 '15 at 19:59

1 Answers1

5

Based on the types, this is a good application of liftIO. liftIO has a type MonadIO m => IO a -> m a so it can be used like this:

liftIO (print "debug message 1")

The type of that expression can be UI () since UI is an instance of MonadIO and print "debug message 1" has the type IO ().

Mirzhan Irkegulov
  • 17,660
  • 12
  • 105
  • 166
David Young
  • 10,713
  • 2
  • 33
  • 47
  • The only reason to apply liftio then is to wrap the unused result of print so it won't shout at me? – vondip Jun 22 '15 at 20:02
  • 1
    @vondip No. The unused output is `()`. The type of the IO action is `IO ()`. In Haskell, IO actions are first-class values, so the value `print "debug message 1"` is the IO action that prints that message, not `()`. – David Young Jun 22 '15 at 20:03
  • 1
    To give another example, if you want to read in a `String` from `stdin` inside of `UI`, you could write: `do ... ; someInput <- liftIO getLine ; ...`(note that the type of `getLine` is `IO String`). `liftIO` lifts IO actions. – David Young Jun 22 '15 at 20:09
  • By the way: if you wanted to print to the console in response to a button click or some other UI event, rather than during the GUI initialisation, you would use either [`onEvent`](http://hackage.haskell.org/package/threepenny-gui-0.6.0.2/docs/Graphics-UI-Threepenny-Core.html#v:onEvent) or [`on`](http://hackage.haskell.org/package/threepenny-gui-0.6.0.2/docs/Graphics-UI-Threepenny-Core.html#v:on). In that case, the `liftIO` would appear in the `(a -> UI void)` callback passed to `onEvent`/`on`. – duplode Jun 23 '15 at 00:58