haskellthreepenny-gui

How to obtain the string value of an Element?


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

Solution

  • 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.