Is there a way I can find the type of shift in the code below by rewriting the instance below? Is the reason I cannot find its type when I try to call it below because it is a local binding (in the where construct)?
class CoMonad m where
extract :: m a -> a
(<<=) :: (m a -> b) -> m a -> m b
instance (Monoid s) => CoMonad ((->) s) where
extract = ($ mempty)
f <<= r = \ t -> (f . shift t) r
where shift t rr = \ s -> rr (s <> t)
:t shift
<interactive>:1:1: error: Variable not in scope: shift
One possibility is giving shift an incomplete signature with a wildcard:
class CoMonad m where
extract :: m a -> a
(<<=) :: (m a -> b) -> m a -> m b
instance (Monoid s) => CoMonad ((->) s) where
extract = ($ mempty)
f <<= r = \ t -> (f . shift t) r
where
shift :: _
shift t rr = \ s -> rr (s <> t)
This will fail to typecheck with an useful error message:
<interactive>:9:15: error:
• Found type wildcard ‘_’ standing for ‘s -> (s -> t) -> s -> t’
Where: ‘t’ is a rigid type variable bound by
the inferred type of shift :: s -> (s -> t) -> s -> t
at <interactive>:10:6-36
‘s’ is a rigid type variable bound by
the instance declaration
at <interactive>:5:10-39
To use the inferred type, enable PartialTypeSignatures
• In the type signature: shift :: _
In an equation for ‘<<=’:
f <<= r
= ...
where
...
In the instance declaration for ‘CoMonad ((->) s)’
• Relevant bindings include
r :: s -> a (bound at <interactive>:7:9)
f :: (s -> a) -> b (bound at <interactive>:7:3)
(<<=) :: ((s -> a) -> b) -> (s -> a) -> s -> b
(bound at <interactive>:7:5)
As Jon Purdy reminds us, the partial signature can also be added inline, as a type annotation:
(\ t -> (f . (shift :: _)) r
If you hadn't actually added the local binding yet, a typed hole (_shift in the example below) would, in a similar way, give you the inferred type for whatever is missing.
\ t -> (f . _shift) r
What is the difference between f1 and f2?
$ ghci -XRankNTypes -XPolyKinds
Prelude> let f1 = undefined :: (forall a m. m a -> Int) -> Int
Prelude> let f2 = undefined :: (forall (a :: k) m. m a -> Int) -> Int
Prelude> :t f1
f1 :: (forall (a :: k) (m :: k -> *). m a -> Int) -> Int
Prelude> :t f2
f2 :: (forall (k :: BOX) (a :: k) (m :: k -> *). m a -> Int) -> Int
Related to this question on RankNTypes and scope of forall. Example taken from the GHC user's guide on kind polymorphism.
f2 requires its argument to be polymorphic in the kind k, while f1 is just polymorphic in the kind itself. So if you define
{-# LANGUAGE RankNTypes, PolyKinds #-}
f1 = undefined :: (forall a m. m a -> Int) -> Int
f2 = undefined :: (forall (a :: k) m. m a -> Int) -> Int
x = undefined :: forall (a :: *) m. m a -> Int
then :t f1 x types fine, while :t f2 x complains:
*Main> :t f2 x
<interactive>:1:4:
Kind incompatibility when matching types:
m0 :: * -> *
m :: k -> *
Expected type: m a -> Int
Actual type: m0 a0 -> Int
In the first argument of ‘f2’, namely ‘x’
In the expression: f2 x
Let's be bloody. We must quantify everything and give the domain of quantification. Values have types; type-level things have kinds; kinds live in BOX.
f1 :: forall (k :: BOX).
(forall (a :: k) (m :: k -> *). m a -> Int)
-> Int
f2 :: (forall (k :: BOX) (a :: k) (m :: k -> *). m a -> Int)
-> Int
Now, in neither example type is k quantified explicitly, so ghc is deciding where to put that forall (k :: BOX), based on whether and where k is mentioned. I am not totally sure I understand or am willing to defend the policy as stated.
Ørjan gives a good example of the difference in practice. Let's be bloody about that, too. I'll write /\ (a :: k). t to make explicit the abstraction that corresponds to forall, and f # type for the corresponding application. The game is that we get to pick the #-ed arguments, but we have to be ready to put up with whatever /\-ed arguments the devil may choose.
We have
x :: forall (a :: *) (m :: * -> *). m a -> Int
and may accordingly discover that f1 x is really
f1 # * (/\ (a :: *) (m :: * -> *). x # a # m)
However, if we try to give f2 x the same treatment, we see
f2 (/\ (k :: BOX) (a :: k) (m :: k -> *). x # ?m0 # ?a0)
?m0 :: *
?a0 :: * -> *
where m a = m0 a0
The Haskell type system treats type application as purely syntactic, so the only way that equation can be solved is by identifying the functions and identifying the arguments
(?m0 :: * -> *) = (m :: k -> *)
(?a0 :: *) = (a :: k)
but those equations are not even well kinded, because k is not free to be chosen: it's being /\-ed not #-ed.
Generally, to get to grips with these uber-polymorphic types, it's good to write out all the quantifiers and then figure out how that turns into your game against the devil. Who chooses what, and in what order. Moving a forall inside an argument type changes its chooser, and can often make the difference between victory and defeat.
The type of f1 places more restrictions on its definition, while the type of f2 places more restrictions on its argument.
That is: the type of f1 requires its definition to be polymorphic in the kind k, while the type of f2 requires its argument to be polymorphic in the kind k.
f1 :: forall (k::BOX). (forall (a::k) (m::k->*). m a -> Int) -> Int
f2 :: (forall (k::BOX) (a::k) (m::k->*). m a -> Int) -> Int
-- Show restriction on *definition*
f1 g = g (Just True) -- NOT OK. f1 must work for all k, but this assumes k is *
f2 g = g (Just True) -- OK
-- Show restriction on *argument* (thanks to Ørjan)
x = undefined :: forall (a::*) (m::*->*). m a -> Int
f1 x -- OK
f2 x -- NOT OK. the argument for f2 must work for all k, but x only works for *
I'm trying to understand why one version of this code compiles, and one version does not.
{-# LANGUAGE RankNTypes, FlexibleContexts #-}
module Foo where
import Data.Vector.Generic.Mutable as M
import Data.Vector.Generic as V
import Control.Monad.ST
import Control.Monad.Primitive
data DimFun v m r =
DimFun {dim::Int, func :: v (PrimState m) r -> m ()}
runFun1 :: (Vector v r, MVector (Mutable v) r) =>
(forall m . (PrimMonad m) => DimFun (Mutable v) m r) -> v r -> v r
runFun1 (DimFun dim t) x | V.length x == dim = runST $ do
y <- thaw x
t y
unsafeFreeze y
runFun2 :: (Vector v r, MVector (Mutable v) r) =>
(forall m . (PrimMonad m) => DimFun (Mutable v) m r) -> v r -> v r
runFun2 t x = runST $ do
y <- thaw x
evalFun t y
unsafeFreeze y
evalFun :: (PrimMonad m, MVector v r) => DimFun v m r -> v (PrimState m) r -> m ()
evalFun (DimFun dim f) y | dim == M.length y = f y
runFun2 compiles fine (GHC-7.8.2), but runFun1 results in errors:
Could not deduce (PrimMonad m0) arising from a pattern
from the context (Vector v r, MVector (Mutable v) r)
bound by the type signature for
tfb :: (Vector v r, MVector (Mutable v) r) =>
(forall (m :: * -> *). PrimMonad m => TensorFunc m r) -> v r -> v r
at Testing/Foo.hs:(26,8)-(28,15)
The type variable ‘m0’ is ambiguous
Note: there are several potential instances:
instance PrimMonad IO -- Defined in ‘Control.Monad.Primitive’
instance PrimMonad (ST s) -- Defined in ‘Control.Monad.Primitive’
In the pattern: TensorFunc _ f
In an equation for ‘tfb’:
tfb (TensorFunc _ f) x
= runST
$ do { y <- thaw x;
f y;
unsafeFreeze y }
Couldn't match type ‘m0’ with ‘ST s’
because type variable ‘s’ would escape its scope
This (rigid, skolem) type variable is bound by
a type expected by the context: ST s (v r)
at Testing/Foo.hs:(29,26)-(32,18)
Expected type: ST s ()
Actual type: m0 ()
Relevant bindings include
y :: Mutable v s r (bound at Testing/Foo.hs:30:3)
f :: forall (v :: * -> * -> *).
MVector v r =>
v (PrimState m0) r -> m0 ()
(bound at Testing/Foo.hs:29:19)
In a stmt of a 'do' block: f y
In the second argument of ‘($)’, namely
‘do { y <- thaw x;
f y;
unsafeFreeze y }’
Could not deduce (s ~ PrimState m0)
from the context (Vector v r, MVector (Mutable v) r)
bound by the type signature for
tfb :: (Vector v r, MVector (Mutable v) r) =>
(forall (m :: * -> *). PrimMonad m => TensorFunc m r) -> v r -> v r
at Testing/Foo.hs:(26,8)-(28,15)
‘s’ is a rigid type variable bound by
a type expected by the context: ST s (v r) at Testing/Foo.hs:29:26
Expected type: Mutable v (PrimState m0) r
Actual type: Mutable v s r
Relevant bindings include
y :: Mutable v s r (bound at Testing/Foo.hs:30:3)
f :: forall (v :: * -> * -> *).
MVector v r =>
v (PrimState m0) r -> m0 ()
(bound at Testing/Foo.hs:29:19)
In the first argument of ‘f’, namely ‘y’
In a stmt of a 'do' block: f y
I'm pretty sure the rank-2 type is to blame, possibly caused by a monomorphism restriction. However, as suggested in a previous question of mine, I enabled -XNoMonomorphismRestriction, but got the same error.
What is the difference between these seemingly identical code snippets?
I think that having a rough mental model of the type-level plumbing involved here is essential, so I'm going go talk about "implicit things" in a bit more detail, and scrutinize your problem only after that. Readers only interested in the direct solution to the question may skip to the "Pattern matching on polymorhpic values" subsection and the end.
1. Implicit function arguments
Type arguments
GHC compiles Haskell to a small intermediate language called Core, which is essentially a rank-n polymorphic typed lambda calculus called System F (plus some extensions). Below I am going use Haskell alongside a notation somewhat resembling Core; I hope it's not overly confusing.
In Core, polymorphic functions are functions which take types as additional arguments, and arguments further down the line can refer to those types or have those types:
-- in Haskell
const :: forall (a :: *) (b :: *). a -> b -> a
const x y = x
-- in pseudo-Core
const' :: (a :: *) -> (b :: *) -> a -> b -> a
const' a b x y = x
This means that we must also supply type arguments to these functions whenever we want to use them. In Haskell type inference usually figures out the type arguments and supplies them automatically, but if we look at the Core output (for example, see this introduction for how to do that), type arguments and applications are visible everywhere. Building a mental model of this makes figuring out higher-rank code a whole lot easier:
-- Haskell
poly :: (forall a. a -> a) -> b -> (Int, b)
poly f x = (f 0, f x)
-- pseudo-Core
poly' :: (b :: *) -> ((a :: *) -> a -> a) -> b -> (Int, b)
poly' b f x = (f Int 0, f b x)
And it makes clear why some things don't typecheck:
wrong :: (a -> a) -> (Int, Bool)
wrong f = (f 0, f True)
wrong' :: (a :: *) -> (a -> a) -> (Int, Bool)
wrong' a f = (f ?, f ?) -- f takes an "a", not Int or Bool.
Class constraint arguments
-- Haskell
show :: forall a. Show a => a -> String
show x = show x
-- pseudo-Core
show' :: (a :: *) -> Show a -> a -> String
show' a (ShowDict showa) x = showa x
What is ShowDict and Show a here? ShowDict is just a Haskell record containing a show instance, and GHC generates such records for each instance of a class. Show a is just the type of this instance record:
-- We translate classes to a record type:
class Show a where show :: a -> string
data Show a = ShowDict (show :: a -> String)
-- And translate instances to concrete records of the class type:
instance Show () where show () = "()"
showUnit :: Show ()
showUnit = ShowDict (\() -> "()")
For example, whenever we want to apply show, the compiler has to search the scope in order to find a suitable type argument and an instance dictionary for that type. Note that while instances are always top level, quite often in polymorphic functions the instances are passed in as arguments:
data Foo = Foo
-- instance Show Foo where show _ = "Foo"
showFoo :: Show Foo
showFoo = ShowDict (\_ -> "Foo")
-- The compiler fills in an instance from top level
fooStr :: String
fooStr = show' Foo showFoo Foo
polyShow :: (Show a, Show b) => a -> b -> String
polyShow a b = show a ++ show b
-- Here we get the instances as arguments (also, note how (++) also takes an extra
-- type argument, since (++) :: forall a. [a] -> [a] -> [a])
polyShow' :: (a :: *) -> (b :: *) -> Show a -> Show b -> a -> b -> String
polyShow' a b (ShowDict showa) (ShowDict showb) a b -> (++) Char (showa a) (showb b)
Pattern matching on polymorphic values
In Haskell, pattern matching on functions doesn't make sense. Polymorphic values can be also viewed as functions, but we can pattern match on them, just like in OP's erroneous runfun1 example. However, all the implicit arguments must be inferable in the scope, or else the mere act of pattern matching is a type error:
import Data.Monoid
-- it's a type error even if we don't use "a" or "n".
-- foo :: (forall a. Monoid a => (a, Int)) -> Int
-- foo (a, n) = 0
foo :: ((a :: *) -> Monoid a -> (a, Int)) -> Int
foo f = ? -- What are we going to apply f to?
In other words, by pattern matching on a polymorphic value, we assert that all implicit arguments have been already applied. In the case of foo here, although there isn't a syntax for type application in Haskell, we can sprinkle around type annotations:
{-# LANGUAGE ScopedTypeVariables, RankNTypes #-}
foo :: (forall a. Monoid a => (a, Int)) -> Int
foo x = case (x :: (String, Int)) of (_, n) -> n
-- or alternatively
foo ((_ :: String), n) = n
Again, pseudo-Core makes the situation clearer:
foo :: ((a :: *) -> Monoid a -> (a, Int)) -> Int
foo f = case f String monoidString of (_ , n) -> n
Here monoidString is some available Monoid instance of String.
2. Implicit data fields
Implicit data fields usually correspond to the notion of "existential types" in Haskell. In a sense, they are dual to implicit function arguments with respect to term obligations:
When we construct functions, the implicit arguments are available in the function body.
When we apply functions, we have extra obligations to fulfill.
When we construct data with implicit fields, we must supply those extra fields.
When we pattern match on data, the implicit fields also come into scope.
Standard example:
{-# LANGUAGE GADTs #-}
data Showy where
Showy :: forall a. Show a => a -> Showy
-- pseudo-Core
data Showy where
Showy :: (a :: *) -> Show a -> a -> Showy
-- when constructing "Showy", "Show a" must be also available:
someShowy :: Showy
someShowy = Showy (300 :: Int)
-- in pseudo-Core
someShowy' = Showy Int showInt 300
-- When pattern matching on "Showy", we get an instance in scope too
showShowy :: Showy -> String
showShowy (Showy x) = show x
showShowy' :: Showy -> String
showShowy' (Showy a showa x) = showa x
3. Taking a look at OP's example
We have the function
runFun1 :: (Vector v r, MVector (Mutable v) r) =>
(forall m . (PrimMonad m) => DimFun (Mutable v) m r) -> v r -> v r
runFun1 dfun#(DimFun dim t) x | V.length x == dim = runST $ do
y <- thaw x
t y
unsafeFreeze y
Remember that pattern matching on polymorphic values asserts that all implicit arguments are available in the scope. Except that here, at the point of pattern matching there is no m at all in scope, let alone a PrimMonad instance for it.
With GHC 7.8.x it's is good practice to use type holes liberally:
runFun1 :: (Vector v r, MVector (Mutable v) r) =>
(forall m . (PrimMonad m) => DimFun (Mutable v) m r) -> v r -> v r
runFun1 (DimFun dim t) x | V.length x == dim = _
Now GHC will duly display the type of the hole, and also the types of the variables in the context. We can see that t has type Mutable v (PrimState m0) r -> m0 (), and we also see that m0 is not listed as bound anywhere. Indeed, it is a notorious "ambiguous" type variable conjured up by GHC as a placeholder.
So, why don't we try manually supplying the arguments, just as in the prior example with the Monoid instance? We know that we will use t inside an ST action, so we can try fixing m as ST s and GHC automatically applies the PrimMonad instance for us:
runFun1 :: forall v r. (Vector v r, MVector (Mutable v) r) =>
(forall m . (PrimMonad m) => DimFun (Mutable v) m r) -> v r -> v r
runFun1 (DimFun dim (t :: Mutable v s r -> ST s ())) x
| V.length x == dim = runST $ do
y <- thaw x
t y
unsafeFreeze y
... except it doesn't work and we get the error "Couldn't match type ‘s’ with ‘s1’ because type variable ‘s1’ would escape its scope".
It turns out - comes as no surprise - that we've forgotten about yet another implicit argument. Recall the type of runST:
runST :: (forall s. ST s a) -> a
We can imagine that runST takes a function of type ((s :: PrimState ST) -> ST s a), and then our code looks like this:
runST $ \s -> do
y <- thaw x -- y :: Mutable v s r
t y -- error: "t" takes a "Mutable v s r" with a different "s".
unsafeFreeze y
The s in t's argument type is silently introduced at the outermost scope:
runFun1 :: forall v s r. ...
And thus the two s-es are distinct.
A possible solution is to pattern match on the DimFun argument inside the ST action. There, the correct s is in scope, and GHC can supply ST s as m:
runFun1 :: forall v r. (Vector v r, MVector (Mutable v) r) =>
(forall m . PrimMonad m => DimFun (Mutable v) m r) -> v r -> v r
runFun1 dimfun x = runST $ do
y <- thaw x
case dimfun of
DimFun dim t | dim == M.length y -> t y
unsafeFreeze y
With some parameters made explicit:
runST $ \s -> do
y <- thaw x
case dimfun (ST s) primMonadST of
DimFun dim t | dim == M.length y -> t y
unsafeFreeze y
As an exercise, let's convert all of the function to pseudo-Core (but let's not desugar the do syntax, because that would be way too ugly):
-- the full types of the functions involved, for reference
thaw :: forall m v a. (PrimMonad m, V.Vector v a) => v a -> m (V.Mutable v (PrimState m) a)
runST :: forall a. (forall s. ST s a) -> a
unsafeFreeze :: forall m v a. (PrimMonad m, Vector v a) => Mutable v (PrimState m) a -> v a
M.length :: forall v s a. MVector v s a -> Int
(==) :: forall a. Eq a => a -> a -> Bool
runFun1 ::
(v :: * -> *) -> (r :: *)
-> Vector v r -> MVector (Mutable v) r
-> ((m :: (* -> *)) -> PrimMonad m -> DimFun (Mutable v) m r)
-> v r -> v r
runFun1 v r vecInstance mvecInstance dimfun x = runST r $ \s -> do
y <- thaw (ST s) v r primMonadST vecInstance x
case dimFun (ST s) primMonadST of
DimFun dim t | (==) Int eqInt dim (M.length v s r y) -> t y
unsafeFreeze (ST s) v r primMonadST vecInstance y
That was a mouthful.
Now we are well-equipped to explain why runFun2 worked:
runFun2 :: (Vector v r, MVector (Mutable v) r) =>
(forall m . (PrimMonad m) => DimFun (Mutable v) m r) -> v r -> v r
runFun2 t x = runST $ do
y <- thaw x
evalFun t y
unsafeFreeze y
evalFun :: (PrimMonad m, MVector v r) => DimFun v m r -> v (PrimState m) r -> m ()
evalFun (DimFun dim f) y | dim == M.length y = f y
evalFun is just a polymorphic function that gets called in the right place (we ultimately pattern match on t in the right place), where the correct ST s is available as the m argument.
As a type system gets more sophisticated, pattern matching becomes a progressively more serious affair, with far-reaching consequences and non-trivial requirements. At the end of the spectrum you find full-dependent languages and proof assistants such as Agda, Idris or Coq, where pattern matching on a piece of data can mean accepting an arbitrary logical proposition as true in a certain branch of your program.
Though #AndrasKovacs gave a great answer, I think it is worth pointing out how to avoid this nastiness altogether. This answer to a related question by me shows how the "correct" definition for DimFun makes all of the rank-2 stuff go away.
By defining DimFun as
data DimFun v r =
DimFun {dim::Int, func :: forall s . (PrimMonad s) => v (PrimState s) r -> s ()}
runFun1 becomes:
runFun1 :: (Vector v r)
=> DimFun (Mutable v) r -> v r -> v r
runFun1 (DimFun dim t) x | dim == V.length x = runST $ do
y <- thaw x
t y
unsafeFreeze y
and compiles without issue.
Pattern-match on a constrained value is not allowed, I think. In particular, you could use a pattern-match, but only for a GADT constructor that fixed the type(s) in the constraint and choose a specific instance. Otherwise, I get the ambiguous type variable error.
That is, I don't think that GHC can unify the type of a value matching the pattern (DimFun dim t) with the type (forall m . (PrimMonad m) => DimFun (Mutable v) m r).
Note that the pattern match in evalFun looks similar, but it is allowed to put constraints on m since the quantification is scoped over the whole evalFun; in constrast, runFun1 as a smaller scope for the quantification of m.
HTH
When compiling this program in GHC:
import Control.Monad
f x = let
g y = let
h z = liftM not x
in h 0
in g 0
I receive an error:
test.hs:5:21:
Could not deduce (m ~ m1)
from the context (Monad m)
bound by the inferred type of f :: Monad m => m Bool -> m Bool
at test.hs:(3,1)-(7,8)
or from (m Bool ~ m1 Bool, Monad m1)
bound by the inferred type of
h :: (m Bool ~ m1 Bool, Monad m1) => t1 -> m1 Bool
at test.hs:5:5-21
`m' is a rigid type variable bound by
the inferred type of f :: Monad m => m Bool -> m Bool
at test.hs:3:1
`m1' is a rigid type variable bound by
the inferred type of
h :: (m Bool ~ m1 Bool, Monad m1) => t1 -> m1 Bool
at test.hs:5:5
Expected type: m1 Bool
Actual type: m Bool
In the second argument of `liftM', namely `x'
In the expression: liftM not x
In an equation for `h': h z = liftM not x
Why? Also, providing an explicit type signature for f (f :: Monad m => m Bool -> m Bool) makes the error disappear. But this is exactly the same type as the type that Haskell infers for f automatically, according to the error message!
This is pretty straightforward, actually. The inferred types of let-bound variables are implicitly generalised to type schemes, so there’s a quantifier in your way. The generalised type of h is:
h :: forall a m. (Monad m) => a -> m Bool
And the generalised type of f is:
f :: forall m. (Monad m) => m Bool -> m Bool
They’re not the same m. You would get essentially the same error if you wrote this:
f :: (Monad m) => m Bool -> m Bool
f x = let
g y = let
h :: (Monad m) => a -> m Bool
h z = liftM not x
in h 0
in g 0
And you could fix it by enabling the “scoped type variables” extension:
{-# LANGUAGE ScopedTypeVariables #-}
f :: forall m. (Monad m) => m Bool -> m Bool
f x = let
g y = let
h :: a -> m Bool
h z = liftM not x
in h 0
in g 0
Or by disabling let-generalisation with the “monomorphic local bindings” extension, MonoLocalBinds.
I came across a frustrating something in Haskell today.
Here's what happened:
I wrote a function in ghci and gave it a type signature
ghci complained about the type
I removed the type signature
ghci accepted the function
I checked the inferred type
the inferred type was exactly the same as the type I tried to give it
I was very distressed
I discovered that I could reproduce the problem in any let-expression
Gnashing of teeth; decided to consult with the experts at SO
Attempt to define the function with a type signature:
Prelude Control.Monad> let myFilterM f m = do {x <- m; guard (f x); return x} :: (MonadPlus m) => (b -> Bool) -> m b -> m b
<interactive>:1:20:
Inferred type is less polymorphic than expected
Quantified type variable `b' is mentioned in the environment:
m :: (b -> Bool) -> m b -> m b (bound at <interactive>:1:16)
f :: (m b -> m b) -> Bool (bound at <interactive>:1:14)
Quantified type variable `m' is mentioned in the environment:
m :: (b -> Bool) -> m b -> m b (bound at <interactive>:1:16)
f :: (m b -> m b) -> Bool (bound at <interactive>:1:14)
In the expression:
do { x <- m;
guard (f x);
return x } ::
(MonadPlus m) => (b -> Bool) -> m b -> m b
In the definition of `myFilterM':
myFilterM f m
= do { x <- m;
guard (f x);
return x } ::
(MonadPlus m) => (b -> Bool) -> m b -> m b
Defined the function without a type signature, checked the inferred type:
Prelude Control.Monad> let myFilterM f m = do {x <- m; guard (f x); return x}
Prelude Control.Monad> :t myFilterM
myFilterM :: (MonadPlus m) => (b -> Bool) -> m b -> m b
Used the function for great good -- it worked properly:
Prelude Control.Monad> myFilterM (>3) (Just 4)
Just 4
Prelude Control.Monad> myFilterM (>3) (Just 3)
Nothing
My best guess as to what is going on:
type annotations somehow don't work well with let-expressions, when there's a do-block.
For bonus points:
is there a function in the standard Haskell distribution that does this? I was surprised that filterM does something very different.
The problem is the precedence of the type operator (::). You're trying to describe the type of myFilterM but what you're actually doing is this:
ghci> let myFilterM f m = (\
do {x <- m; guard (f x); return x} \
:: \
(MonadPlus m) => (b -> Bool) -> m b -> m b)\
)
(backslashes inserted for readability only, not legit ghci syntax)
Do you see the issue? I get the same problem for something simple like
ghci> let f x = x + 1 :: (Int -> Int)
<interactive>:1:15:
No instance for (Num (Int -> Int))
arising from the literal `1'
Possible fix: add an instance declaration for (Num (Int -> Int))
In the second argument of `(+)', namely `1'
In the expression: x + 1 :: Int -> Int
In an equation for `f': f x = x + 1 :: Int -> Int
The solution is to attach the type signature to the proper element:
ghci> let f :: Int -> Int ; f x = x + 1
ghci> let myFilterM :: (MonadPlus m) => (b -> Bool) -> m b -> m b; myFilterM f m = do {x <- m; guard (f x); return x}
And for bonus points, you want mfilter (hoogle is your friend).
This is likely just an issue of type annotation syntax and binding precendence. If you write your example as,
let myFilterM :: (MonadPlus m) => (b -> Bool) -> m b -> m b; myFilterM f m = do {x <- m; guard (f x); return x}
then GHCi will give you a high-five and send you on your way.
I don't know what kind of compiler you use, but on my platform (GHC 7.0.3) I get a simple type mismatch:
$ ghci
GHCi, version 7.0.3: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package ffi-1.0 ... linking ... done.
Prelude> :m +Control.Monad
Prelude Control.Monad> let myFilterM f m = do {x <- m; guard (f x); return x} :: (MonadPlus m) => (b -> Bool) -> m b -> m b
<interactive>:1:30:
Could not deduce (t1 ~ ((b1 -> Bool) -> m1 b1 -> m1 b1))
from the context (MonadPlus m)
bound by the inferred type of
myFilterM :: MonadPlus m => t -> t1 -> (b -> Bool) -> m b -> m b
at <interactive>:1:5-100
or from (MonadPlus m1)
bound by an expression type signature:
MonadPlus m1 => (b1 -> Bool) -> m1 b1 -> m1 b1
at <interactive>:1:21-100
`t1' is a rigid type variable bound by
the inferred type of
myFilterM :: MonadPlus m => t -> t1 -> (b -> Bool) -> m b -> m b
at <interactive>:1:5
In a stmt of a 'do' expression: x <- m
In the expression:
do { x <- m;
guard (f x);
return x } ::
MonadPlus m => (b -> Bool) -> m b -> m b
In an equation for `myFilterM':
myFilterM f m
= do { x <- m;
guard (f x);
return x } ::
MonadPlus m => (b -> Bool) -> m b -> m b
<interactive>:1:40:
Could not deduce (t ~ ((m1 b1 -> m1 b1) -> Bool))
from the context (MonadPlus m)
bound by the inferred type of
myFilterM :: MonadPlus m => t -> t1 -> (b -> Bool) -> m b -> m b
at <interactive>:1:5-100
or from (MonadPlus m1)
bound by an expression type signature:
MonadPlus m1 => (b1 -> Bool) -> m1 b1 -> m1 b1
at <interactive>:1:21-100
`t' is a rigid type variable bound by
the inferred type of
myFilterM :: MonadPlus m => t -> t1 -> (b -> Bool) -> m b -> m b
at <interactive>:1:5
The function `f' is applied to one argument,
but its type `t' has none
In the first argument of `guard', namely `(f x)'
In a stmt of a 'do' expression: guard (f x)
Prelude Control.Monad>
I guess the problem lies in the fact, that the :: does not reaches the argument. This small variation (note the separate type declaration)
let myFilterM f m = do {x <- m; guard (f x); return x}; myFilterM :: (MonadPlus m) => (b -> Bool) -> m b -> m b
runs without problems. It may be related to the new type-checker in GHC 7.