Type signature "Maybe a" doesn't like "Just [Event]" - haskell

I'm still learning Haskell and need help with the type inference please!
Using packages SDL and Yampa
I get the following type signature from FRP.Yampa.reactimate:
(Bool -> IO (DTime, Maybe a))
and I want to use it for:
myInput :: Bool -> IO (DTime, Maybe [SDL.Event])
myInput isBlocking = do
event <- SDL.pollEvent
return (1, Just [event])
...
reactimate myInit myInput myOutput mySF
but it says
Couldn't match expected type `()'
against inferred type `[SDL.Event]'
Expected type: IO (DTime, Maybe ())
Inferred type: IO (DTime, Maybe [SDL.Event])
In the second argument of `reactimate', namely `input'
In the expression: reactimate initialize input output process
I thought Maybe a allows me to use anything, even a SDL.Event list?
Why is it expecting Maybe () when the type signature is actually Maybe a?
Why does it want an empty tuple, or a function taking no arguments, or what is () supposed to be?

The full type signature of reactimate is
IO a -- # myInit
-> (Bool -> IO (DTime, Maybe a)) -- # myInput
-> (Bool -> b -> IO Bool) -- # myOutput
-> SF a b -- # mySF
-> IO ()
The same a and b must match, that means if your myInput has type Bool -> IO (DTime, Maybe [SDL.Event]), then all other a must also be [SDL.Event]. Hence, to match the types, you need to ensure
myInit :: IO [SDL.Event] -- # **not** IO ().
mySF :: SF [SDL.Event] b
BTW, () is the unit type.

Related

Haskell: function signature

This program compiles without problems:
bar :: MonadIO m
=> m String
bar = undefined
run2IO :: MonadIO m
=> m String
-> m String
run2IO foo = liftIO bar
When I change bar to foo (argument name),
run2IO :: MonadIO m
=> m String
-> m String
run2IO foo = liftIO foo
I get:
Couldn't match type ‘m’ with ‘IO’
‘m’ is a rigid type variable bound by
the type signature for run2IO :: MonadIO m => m String -> m String
...
Expected type: IO String
Actual type: m String ...
Why are the 2 cases are not equivalent?
Remember the type of liftIO:
liftIO :: MonadIO m => IO a -> m a
Importantly, the first argument must be a concrete IO value. That means when you have an expression liftIO x, then x must be of type IO a.
When a Haskell function is universally quantified (using an implicit or explicit forall), then that means the function caller chooses what the type variable is replaced by. As an example, consider the id function: it has type a -> a, but when you evaluate the expression id True, then id takes the type Bool -> Bool because a is instantiated as the Bool type.
Now, consider your first example again:
run2IO :: MonadIO m => m Integer -> m Integer
run2IO foo = liftIO bar
The foo argument is completely irrelevant here, so all that actually matters is the liftIO bar expression. Since liftIO requires its first argument to be of type IO a, then bar must be of type IO a. However, bar is polymorphic: it actually has type MonadIO m => m Integer.
Fortunately, IO has a MonadIO instance, so the bar value is instantiated using IO to become IO Integer, which is okay, because bar is universally quantified, so its instantiation is chosen by its use.
Now, consider the other situation, in which liftIO foo is used, instead. This seems like it’s the same, but it actually isn’t at all: this time, the MonadIO m => m Integer value is an argument to the function, not a separate value. The quantification is over the entire function, not the individual value. To understand this more intuitively, it might be helpful to consider id again, but this time, consider its definition:
id :: a -> a
id x = x
In this case, x cannot be instantiated to be Bool within its definition, since that would mean id could only work on Bool values, which is obviously wrong. Effectively, within the implementation of id, x must be used completely generically—it cannot be instantiated to a specific type because that would violate the parametricity guarantees.
Therefore, in your run2IO function, foo must be used completely generically as an arbitrary MonadIO value, not a specific MonadIO instance. The liftIO call attempts to use the specific IO instance, which is disallowed, since the caller might not provide an IO value.
It is possible, of course, that you might want the argument to the function to be quantified in the same way as bar is; that is, you might want its instantiation to be chosen by the implementation, not the caller. In that case, you can use the RankNTypes language extension to specify a different type using an explicit forall:
{-# LANGUAGE RankNTypes #-}
run3IO :: MonadIO m => (forall m1. MonadIO m1 => m1 Integer) -> m Integer
run3IO foo = liftIO foo
This will typecheck, but it’s not a very useful function.
In the first, you're using liftIO on bar. That actually requires bar :: IO String. Now, IO happens to be (trivially) an instance on MonadIO, so this works – the compiler simply throws away the polymorphism of bar.
In the second case, the compiler doesn't get to decide what particular monad to use as the type of foo: it's fixed by the environment, i.e. the caller can decide what MonadIO instance it should be. To again get the freedom to choose IO as the monad, you'd need the following signature:
{-# LANGUAGE Rank2Types, UnicodeSyntax #-}
run2IO' :: MonadIO m
=> (∀ m' . MonadIO m' => m' String)
-> m String
run2IO' foo = liftIO foo
... however I don't think you really want that: you might then as well write
run2IO' :: MonadIO m => IO String -> m String
run2IO' foo = liftIO foo
or simply run2IO = liftIO.

Why does bracket require `release` to produce result that is ignored?

bracket
:: IO a -- ^ computation to run first (\"acquire resource\")
-> (a -> IO b) -- ^ computation to run last (\"release resource\")
-> (a -> IO c) -- ^ computation to run in-between
-> IO c -- returns the value from the in-between computation
bracket before after thing =
mask $ \restore -> do
a <- before
r <- restore (thing a) `onException` after a
_ <- after a
return r
Is this related to some API design pattern or conventions ? Why not use the following part of signature?
-> (a -> IO ()) -- ^ computation to run last (empty result)
or
-> (a -> IO a) -- ^ computation to run last (`a` cannot be ignored)
I think you have it backwards - bracket will ignore the result of the release operation for you.
If the signature of the release operation was a -> IO () then you would have to supply a function which always returned (). By making the signature a -> IO b your release function can return anything since
the type variable b is not referenced anywhere else in the signature -i.e.
it is totally unrelated to any of the other type variables.

How to combine two different monads

I'm testing a REST server. I hit it in the IO monad and simulate it in State Db where Db tracks the supposed state of the server. The following function is supposed to run both versions and compare the results...
check :: (Eq a, MonadState d s) => s a -> IO a -> s (IO Bool)
-- or: check :: (Eq a, MonadState d s, MonadIO i) => s a -> i a -> s (i Bool)
check _ _ = (return.return) False -- for now
but when I try it with these simplest possible functions ...
simReset :: State Db ()
realReset :: IO ()
reset :: StateT Db IO Bool
reset = check simReset realReset
I get this error:
Couldn't match expected type `Bool' with actual type `IO Bool'
Expected type: StateT Db IO Bool
Actual type: StateT Db IO (IO Bool)
In the return type of a call of `check'
In the expression: check simReset realReset
Why? And how do I fix it?
(This topic started here: Lift to fix the *inside* of a monad transformer stack)
In your implementation, check is going to return an IO Bool regardless of what the state monad s is. So, when you pass simReset to check, which is a monadic action in the State Db monad, the return value is going to be State Db (IO Bool).
How to fix it depends on what you're trying to do. Based on your implementation of reset it seems like you're trying to interface with a transformer stack of the form StateT Db IO a. In this case, you're describing a kind of program in the context of StateT Db IO. There are two ways to go about this:
You can upgrade simReset to have type MonadState Db s => s () (This shouldn't actually require any implementation change).
You can define an auxiliary function that "hoists" it into the proper monad
For example:
hoistState :: Monad m => State s a -> StateT s m a
hoistState prg = StateT $ \st -> return $ runState prg st
In either case, you'll probably want to keep the action that you're performing and the result in the same monad:
check :: (Eq a, MonadIO s, MonadState d s) => s a -> IO a -> s Bool
Then, with solution one, you have
reset = check simReset realReset
And with solution two you have:
reset = check (hoistState simReset) realReset

Unable to figure out what the type of a function is

I have this function:
import Data.Aeson
import Network.HTTP.Conduit
getJSON url = eitherDecode <$> simpleHttp url
which is called as:
maybeJson <- getJSON "https://abc.com" :: IO (Either String Value)
However, I can't figure out what the type of getJSON is. I've been trying these:
getJSON :: FromJSON a => String -> Either String a --1
getJSON :: String -> Either String Value --2
plus some other ones but failed. What is it?
The main thing you're missing in your attempts so far is the IO type. One correct type given your current usage is
getJSON :: String -> IO (Either String Value)
You can see that the IO type must be needed given your maybeJSON line - that makes it clear that getJSON <something> returns IO (Either String Value).
In fact the exact type is more general:
getJSON :: (FromJSON a, MonadIO m, Functor m) => String -> m (Either String a)
To go into more detail on how to derive the correct type, we need to look carefully at the types of simpleHttp and eitherDecode:
eitherDecode :: FromJSON a => ByteString -> Either String a
simpleHttp :: MonadIO m => String -> m ByteString
They're also being combined with (<$>) from Control.Applicative:
(<$>) :: Functor f => (a -> b) -> f a -> f b
Putting it all together gives the type above - the f for (<$>) and the m for simpleHttp must be the same, and the input type is the String being fed into simpleHttp, and the result type is the result type of eitherDecode, lifted into m by the (<$>) operation.
You can also just ask GHC to tell you the answer. Either load your module up in ghci and use :t getJSON, or leave out the type signature, compile with -Wall and look at the warning about the missing type signature for getJSON.
Note that you don't have to explicitly declare a type for your functions in Haskell. The compiler will deduce them for you. In fact, you can use the :type command (or just :t for short) in ghci to let the compiler tell you the type of a function after you load the source file.

Haskell: GHC cannot deduce type. Rigid type variable bound by the type signature error

I'v seen a couple of posts with a similar subject but they don't really help me to solve my problem. So I dare to repeat.
Now I have a functions with signature:
run' :: Expr query => RethinkDBHandle -> query -> IO [JSON]
this is a database query run function.
I wrap this function in a pool (pool is already created and irrelevant to the question) to simplify connections.
rdb q = withResource pool (\h -> run' (use h $ db "test") q)
Essentially, this function has exact the same signature as the run above.
The problem is that if I use the function without a signature then all is good and GHC is happy figuring things out. As soon as I specify the signature it stops working on certain input complaining about not being able to deduce the type.
There are mainly two input types that are used as query input.
ReQL and Table
Both of those types are instances of Expr so they both accepted by GHC.
As soon as I put the signature everything stops working and GHC coplains about not being able to deduce the type and gives me "rigid type variable bound by the type signature" error. If I make signature more specific like ReQL instead of Expr a, then obveously it stops accepting Table input and visa versa. Specifying input as Expr a, which both ReQL and Table are instances of, stops with the error above. Dropping the signature all together works fine.
So how do I solve this? Dropping the signature feels wrong.
I don't know if I should make the question more generic or more specific but if it helps this is the library with all the types and instances to help with an advice.
Rethink DB
UPDATE
As requested, this is the full code listing producing the error.
main = do
pool <- createPool (connect "localhost" 28015 Nothing) close 1 300 5
let rdb q = withResource pool (\h -> run' (use h $ db "test") q)
scotty 3000 $ basal rdb
basal :: Expr q => (q -> IO [JSON]) -> ScottyM ()
basal r = get "/json" $ showJson r
showJson :: Expr q => (q -> IO [JSON]) -> ActionM ()
showJson r = do
j <- lift $ r $ table "mytable"
text $ T.pack $ show j
And this is the full error listing
Main.hs:19:17:
No instance for (Expr q0) arising from a use of `basal'
The type variable `q0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance Expr () -- Defined in `Database.RethinkDB.ReQL'
instance (Expr a, Expr b) => Expr (a, b)
-- Defined in `Database.RethinkDB.ReQL'
instance (Expr a, Expr b, Expr c) => Expr (a, b, c)
-- Defined in `Database.RethinkDB.ReQL'
...plus 24 others
In the second argument of `($)', namely `basal rdb'
In a stmt of a 'do' block: scotty 3000 $ basal rdb
In the expression:
do { pool <- createPool
(connect "localhost" 28015 Nothing) close 1 300 5;
let rdb q = withResource pool (\ h -> ...);
scotty 3000 $ basal rdb }
Main.hs:26:19:
Could not deduce (q ~ Table)
from the context (Expr q)
bound by the type signature for
showJson :: Expr q => (q -> IO [JSON]) -> ActionM ()
at Main.hs:24:13-52
`q' is a rigid type variable bound by
the type signature for
showJson :: Expr q => (q -> IO [JSON]) -> ActionM ()
at Main.hs:24:13
In the return type of a call of `table'
In the second argument of `($)', namely `table "mytable"'
In the second argument of `($)', namely `r $ table "mytable"'
Thank you
Reading the error messages it seems the first problem is that the type you specify for showJson is wrong.
As r is being applied directly to table which is table :: String -> Table its type is not
r :: Expr q => q -> IO [JSON]
but instead either
r :: Table -> IO [JSON]
or (using RankNTypes)
r :: forall q . Expr q => q -> IO [JSON]
The first is simpler and more direct while the second is probably closer to your intended meaning---it can be read as "fromJson takes an input which it demands uses only the Expr interface on its argument" instead of "fromJson takes any kind of input which happens to use an Expr instantiated type as its argument". For instance, with the type you've given
fromJson (undefined :: Query -> IO [JSON])
would unify as well... but clearly that's now how r is being used in the function body.
(In particular, it has to do with the positivity of the parameter q. Due to the way this function is written, q acts more like an output argument than an input argument. Indeed, the function creates a Table (with table) instead of demanding one. The argument you've written thus implies that we have a function Expr q => Table -> q.)
Now, this specificity of type transmits upward as well causing basal to have the type
basal :: (Table -> IO [JSON]) -> ScottyM ()
or
basal :: (forall q . Expr q => q -> IO [JSON]) -> ScottyM ()
and thus leading to your Cannot deduce (q ~ Table) error.
At this point I can't be sure why stating an explicit type for rdb would lead to issues, but it may be that clearing this one will stop problems from occurring there. Usually once you've already broken the type system it's very hard to predict its behavior in other locations.

Resources