1

I want to do something like this:

getValue :: Element -> String
getValue x = do
    v <- get UI.value x
    v

However, an error is thrown; the expected type of get UI.value x is [String] but the actual type is UI String?

But if I change the type signature to getValue :: Element -> UI String, my last v gets the error of expected type UI String while its actual type is String.

I'm trying to implement something like this:

myfunction window = do
    words <- getElementsByClassName window "word"
    let strs = map getValue words

Since I can't say let strs = map (\x -> v <- get UI.value x) words.

When I only have one element to deal with, I'm fine:

filename <- chooser # get UI.value
liftIO $ print filename
unless (null filename) $ do
    prevRows <- getElementsByClassName w "row"
    mapM_ delete prevRows
    elems <- liftIO $ readJSON filename
    mapM_ (element table # addRow) elems
Cactus
  • 27,075
  • 9
  • 69
  • 149
allidoiswin
  • 2,543
  • 1
  • 20
  • 23
  • 1
    Presumably you just want `getValue :: Element -> UI String; getValue = get UI.value`. Possibly not even worth making a definition. Disclaimer: I have never used threepenny or even looked at its documentation, so this is speculation based on the info in the question rather than expertise. – Daniel Wagner Dec 03 '15 at 23:41
  • So threepenny uses a UI monad, kind of like IO. `get UI.value` would return a `UI String`, which I'm trying to use `<-` on. – allidoiswin Dec 04 '15 at 01:41

1 Answers1

3

Since get UI.value x has type UI String as opposed to String, the correct definition of getValue needs to be in the UI monad as well:

-- Still not well-typed
getValue :: Element -> UI String
getValue x = do
    v <- get UI.value x
    v

However, then your next problem is that after you bind get UI.value x to v, v has type String, not UI String, so you need to return it, leading to the correct version

getValue :: Element -> UI String
getValue x = do
    v <- get UI.value x
    return v

which of course can be simplified as

getValue :: Element -> UI String
getValue x = get UI.value x

or η-reduced further to

getValue :: Element -> UI String
getValue = get UI.value

Since UI is a monad, you can use standard monad combinators like mapM to turn getValue :: Element -> UI String into mapM getValue :: [Element] -> UI [String]:

myfunction window = do
    words <- getElementsByClassName window "word"
    strs <- mapM (get UI.value) words
    -- ... rest of `myfunction` can use `strs`

Note that myfunction of course is still in UI.

Cactus
  • 27,075
  • 9
  • 69
  • 149
  • 2
    @allidoiswin You cannot get a `String` out of a `UI String`. But you can teach an operation that's expecting a `String` how to deal with getting a `UI String` instead; and that is what you are doing with `readFile`: teaching an operation that knows how to muck with a `FilePath` how to muck with a `UI FilePath` instead. The `do` syntax tries to hide this inversion of control -- but as you are observing, not very well, so if you have this wrong impression of what can be done, you will be confused often! – Daniel Wagner Dec 04 '15 at 03:10
  • @DanielWagner could you link me to a resource for this? Very interesting. – allidoiswin Dec 04 '15 at 04:01
  • @allidoiswin There are many, many monad tutorials out there. When I was learning, I especially enjoyed [You Could Have Invented Monads](http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html) and [All About Monads](https://wiki.haskell.org/All_About_Monads). – Daniel Wagner Dec 04 '15 at 04:49