Работая над вычислением ввода-вывода, я получил лестницу из case mbValue of …
s и понял, что для упрощения кода мне следует использовать монаду Maybe
. Так как это внутри вычисления IO
и мне нужно получить IO
значений, я использовал преобразователь монады MaybeT
, чтобы я мог lift
IO
вычислить в Maybe
.
Я всегда думал о том, что значения «лишаются» их Maybe
ness после values <- mbValue
внутри Maybe
вычисления, но здесь это оказывается слишком простой эвристикой.
Как показано ниже, при использовании значения Maybe a
в качестве a
(здесь путем передачи его в read
) проверка типа не выполняется:
import Control.Monad.Trans (lift)
import Control.Monad.Trans.Maybe (runMaybeT)
lol :: IO (Maybe Int)
lol = return (Just 3)
lal :: IO (Maybe String)
lal = return (Just "8")
foo :: IO (Maybe Bool)
foo = do
b <- runMaybeT $ do
x <- lift lol
y <- lift lal
return (x < (read y))
return b ^-- Couldn't match type ‘Maybe String’ with ‘String’
main = foo >>= print
Если я помещу типизированное отверстие для return (x < (read y))
, я увижу, что он ожидает Bool
, что имеет смысл, но также и то, что текущие привязки включают
|| y :: Data.Maybe.Maybe GHC.Base.String
|| (bound at /private/tmp/test.hs:14:5)
|| x :: Data.Maybe.Maybe GHC.Types.Int
|| (bound at /private/tmp/test.hs:13:5)
То есть y
это Maybe String
. Это, конечно, объясняет ошибку, но я в замешательстве. Где я неправильно понимаю, и как я могу исправить эту ошибку?