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