Let's consider:
f :: Int
f = return 64 >>= (\x -> x^2) >>= (\y -> y^2)
GHCi rejects my code with
Couldn't match expected type `Int' with actual type `m0 b0'
In the expression: return 64 >>= (\ x -> x ^ 2) >>= (\ y -> y ^ 2)
In an equation for `f':
f = return 64 >>= (\ x -> x ^ 2) >>= (\ y -> y ^ 2)
Failed, modules loaded: none.
The result should be or at least related to 281,474,976,710,656 (64 squared followed by raising the result to the fourth power).
I cannot solve this problem. And it is connected with my misunderstanding of monads. Please help.
We need to look at (>>=). It has type
(>>=) :: Monad m => m a -> (a -> m b) -> m b
In english: the second argument of (>>=) must be function that produces a monadic value. Your functions just produce numbers.
The confusion comes about because you state that f will be an Int. Yet the compiler knows that (>>=) will return a m b
Thus the error message: because of your annotation it expected to find Int, but all it got was m0 b0
Note that your code for f could be correct for a type that is both a number with a sensible implementation of (^) and a monad. But Int is not such a type.
What you want is probably:
f = return 64 >>= pure . (^2) >>= pure . (^4)
or
f = (\x -> (x^2)^4) <$> return 64
But this will still not be a plain Int but an Int in some monad! Thus:
f :: Monad m => m Int
(I think you'll have to turn off the monomorphism restriction to make this actually compile.)
Related
In Haskell Monad is declared as
class Applicative m => Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
return = pure
I was wondering if it is okay to redeclare the bind operator as
(>>=) :: (a -> m b) -> m a -> m b
?
Is it correct that the second declaration makes it clearer that (>>=) maps a function of type a -> m b to a function of type m a -> m b, while the original declaration makes less clear what it means?
Will that change of declaration make something from possible to impossible, or just require some change of using monad (which seems bearable to Haskell programmers)?
Thanks.
There's one reason why >>= tends to be more useful in practice than it's flipped counterpart =<<: it plays nicely with lambda notation. Namely, \ acts as a syntactic herald, so you can continue the computation without needing any parentheses. For instance,
do x <- [1..5]
y <- [10..20]
return $ x*y
can be rewritten very easily in terms of >>= as
[1..5] >>= \x -> [10..20] >>= \y -> return $ x*y
You still have much the same “imperative flow” feel as with the do version.
Whereas with =<< it would require awkward parentheses and seem to read backwards:
(\x -> (\y -> return $ x*y) =<< [10..20]) =<< [1..5]
Ok, you might say this feels more like function application. But where that is useful, it is often more poignant to use only the applicative functor interface rather than the monadic one:
(\x y -> x*y) <$> [1..5] <*> [10..20]
or short
(*) <$> [1..5] <*> [10..20]
Note that (<*>) :: f (a->b) -> f a -> f b has essentially the order of =<< that you propose, just with the a-> inside the functor rather than outside.
the Cont r a type stands for a function which takes a continuation a->r and produces a result of type r. So both the continuation and the entire Cont r a produce a result of the same type r.
My question is: are the two results necessarily the same value, or can a Cont r a post-process the result from the continuation and produce a different value, albeit of the same type r?
I tried using (+1) for post-processing (note the + 1 --<--):
c1 :: Int -> Cont r Int
c1 x = let y = 2*x
in cont $ \k -> (k y) + 1 --<--
Now that doesn't typecheck, because my post-processing function (+1) only accepts an argument whose type belongs to the Num typeclass. However, I pass the result of the continuation (k y) which is of some type r that is not guaranteed to belong to the Num typeclass.
Whatever I do to (k y), it must be a function of type r->r. The only function which can do this for all r is the id function and using id for post-processing is no post-processing at all.
However, the whole thing does typecheck if I restrict r to the Num typeclass or even to the concrete type Int. It then produces the expected result:
*Main> runCont (c1 1) id
3
I am quite unsure,
if such post-processing and restricting the type of r is a normal thing to do, and if so, in what circumstances this might be useful
or if the type variable rhas to be read as for all r and restricting the type of r will lead to all sorts of trouble.
Can someone shed some light on this?
Technically, I think it's fine. Specializing Cont r a to Num r => Cont r a doesn't seem fundamentally more problematic than specializing Reader r a to Num r => Reader r a.
An implication of doing so is that the resulting CPS computation can only be run against a (final) continuation that produces a number, but that's obvious -- if you have a computation that post-processes the continuation result as a number, it can only be used with continuations that produce numbers!
As additional evidence that this is sanctioned at least to some degree, note that there's a function:
mapCont :: (r -> r) -> Cont r a -> Cont r a
If this function was to be used with no restriction on r, the only valid values for its first argument would be id or functions that don't terminate, as you have noted.
A version of your c1 using mapCont might look like:
c2 :: (Num r) => Int -> Cont r Int
c2 x = mapCont (+1) $ return (2*x)
and seems to work fine:
> runCont (c2 10) id
21
> runCont (c2 10) (const 5)
6
> runCont (c2 10) show
... No instance for (Num String) arising from a use of 'c2' ...
As for when this would be useful, I'm not sure. I can think of a few somewhat lame applications. You could define an computation that overrides the final result (provided no other kind of post-processing is used):
override x = cont (const x)
to be used like:
> runCont (return 2 >>= \x -> cont (\f -> f (x*3))) id
6
> runCont (return 2 >> override 1000 >>= \x -> cont (\f -> f (x*3))) id
1000
>
or a computation transformer that emulates a writer to add log functionality:
annotate note comp = mapCont (\(a, w) -> (a, note:w)) comp
which you might use like this:
runCont (annotate "two" (return 2)
>>= \x -> annotate "times three" (cont (\f -> f (x*3))))
(\a -> (a, []))
yielding:
(6,["two","times three"])
These don't seem like very compelling applications, though.
#KABuhr has shown that post-processing in the ordinary Cont works, but didn't find "very compelling applications". I'm going to show you how post-processing is useful, but it only works best when you generalize Cont. First, some header stuff (mostly used in the examples):
{-# LANGUAGE RebindableSyntax #-}
import Prelude(Num(..), Eq(..), Enum(..))
import Data.Bool
import Data.Function
import Data.Functor.Identity
import Data.List
import Data.Maybe
import Data.Tuple
import Control.Lens(_1, _2, traversed)
Now, a generalized Cont.
newtype Cont r f a = Cont { runCont :: (a -> r) -> f }
Your question was "is post-processing allowed in Cont?" The answer is yes. If would like it to not be so, you can use newtype ContS a = { runContS :: forall r. (a -> r) -> r } which totally disallows it. In fact, ContS a is isomorphic to a. The Cont I just defined takes the opposite position: even type-changing post-processors are allowed. We can define a standard Functorial (<$>).
infixl 1 <$>
(<$>) :: (a -> b) -> Cont r f a -> Cont r f b
f <$> Cont x = Cont $ \cont -> x $ \realX -> cont (f realX)
Before continuing, let's get an understanding of the metaphor behind Cont. A Cont r f a is a computation that can produce as. It will give you the as, but will ask you to produce rs. Once you do that, it'll make fs. It's sort of like a (r -> f, a), but with heavy restrictions on use. If we try to define an Applicative-ish operator, we see something interesting.
infixl 1 <*>
(<*>) :: Cont m f (a -> b) -> Cont r m a -> Cont r f b
Cont f <*> Cont x = Cont $ \cont -> x $ \realX -> f $ \realF -> cont (realF realX)
(<*>) is sort of doing two operations at once. It is applying the a -> b to an a to get b, but it's also composing the m -> f and r -> m aspects into a r -> f part. However, the type of (<*>) no longer fits into the normal Applicative format. This is why we use Cont r a instead of Cont r f a. The former is less powerful, but it fits into our existing framework. To get our Cont to work, we have to leave some of the established infrastructure behind.
Before we get into the RebindableSyntax-level stuff, here's some usage.
complete :: Cont a f a -> f
complete (Cont x) = x id
amb :: [a] -> Cont (Maybe b) (Maybe (a, b)) a
amb [] = Cont (const Nothing)
amb (x : xs) = Cont $ \test -> case test x of
Nothing -> runCont (amb xs) test
Just y -> Just (x, y)
poly :: Num a => a -> a -> a -> a
poly x y z = sq x * y + sq y + z + sq z * x
where sq x = x * x
solution :: (Num a, Enum a, Eq a) => Maybe (a, (a, (a, ())))
solution = complete $ testRoot <$> amb [-5..5]
<*> amb [-10 .. -5]
<*> amb [5..10]
where testRoot x y z = case poly x y z of
0 -> Just ()
_ -> Nothing
complete completes a computation when there isn't actually a gap holding it up. amb takes a [a], and goes through each a, one by one. It passes each into the test, and searches until it finds one that succeeds. It post-processes the result of the test in two ways. It resets the result until it's a Just (or gives up), and a Just result gets up paired with the input that built it.
In solution, the complete is delimiting the extent of the continuation passed to the ambs. Each amb is passed the code that lies between it and the complete. E.g., the continuation given to the amb [-5..5] is \x -> testRoot x <*> amb [-10 .. -5] <*> amb [10..5]. This style of continuations is called shift/reset. Cont is shift, complete is reset. The idea is that amb [-5..5] is a "liar"; it "looks like" a Num a => a because it's getting passed to testRoot, but it's actually a control structure that turns everything around it inside-out. Compared to the normal Cont r a, the control structures allowed in our Cont are more powerful.
Now, here's what we need RebindableSyntax for:
(=<<) :: (a -> Cont r m b) -> Cont m f a -> Cont r f b
f =<< Cont x = Cont $ \cont -> x $ \realX -> runCont (f realX) cont
(>>=) = flip (=<<)
return :: a -> Cont r r a
return x = Cont ($ x)
(=<<) is the Monad-style function application operator. Again, our version doesn't fit the usual type. With (>>=) and return, do-notation has now been redefined to work with Cont. You can go back and rewrite solution in do-notation to see that it works.
Let's really get out there. The idea behind profunctor optics is that data structures give rise to "transformer transformers". E.g. a Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t takes a transformer between the "small" structures a and b and makes one from between the "bigger" s and t. Look what lies just a flip away...
editing :: ((a -> Identity b) -> s -> Identity t) -> s -> Cont b t a
editing optic x = Cont (runIdentity . flip optic x . (Identity .))
editing, as a control structure, takes a reference to a field inside a structure, a structure to use it on, and then mutates that structure with "the rest of the program." Using it, you can write the following:
example :: (a -> a) -> [(Bool, (a, a))] -> [(Bool, (a, a))]
example f xs = complete $ do x <- editing traversed xs
n2 <- editing _2 x
n <- case fst x of
True -> editing _1 n2
False -> editing _2 n2
return (f n)
I hope, with even these contrived examples, that you're convinced that post-processing is useful in Cont. There's nothing wrong with doing it. However, if you want to use it at its full potential, you have to break out of the existing Applicative and Monad form. This is painful, so we cripple Cont to make it fit, disabling type-changing post-processing as a trade-off.
When I seemed to understand what return is for in Haskell, I tried to play with different alternatives and it seems that return not only can be used anywhere in the monad chain, but also can be excluded completely
*Main> Just 9 >>= \y -> (Just y) >>= \x -> return x
Just 9
*Main> Just 9 >>= \y -> (return y) >>= \x -> (Just y)
Just 9
*Main> Just 9 >>= \y -> (Just y) >>= \x -> (Just x)
Just 9
Even if I omit return in my own instancing, I only get warning...
data MaybeG a = NothingG | JustG a deriving Show
instance Monad MaybeG where
-- return x = JustG x
NothingG >>= f = NothingG
JustG x >>= f = f x
fail _ = NothingG
Monad.hs:3:10:
Warning: No explicit method nor default method for `return'
In the instance declaration for `Monad MaybeG'
and I still can use the monad
*Main> JustG 9 >>= \y -> (JustG 11) >>= \x -> (JustG y)
JustG 9
*Main> JustG 9 >>= \y -> (NothingG) >>= \x -> (JustG y)
NothingG
So what's so special about the return keyword? Is this about more complex cases where I can not omit it? Or because this is the "right" way to do things even if they can be done differently?
UPDATE:
.. or another alternative, I could define my own monadic value constructor
finallyMyLastStepG :: Int -> MaybeG Int
finallyMyLastStepG a = JustG a
and produce another variant of the same chain (with the same result)
*Main> JustG 9 >>= \y -> (JustG 11) >>= \x -> (finallyMyLastStepG y)
JustG 9
So what's so special about the return keyword?
Firstly, return is not a keyword in Haskell. It is an overloaded function.
Its type is given by:
class Monad m where
-- | Sequentially compose two actions, passing any value produced
-- by the first as an argument to the second.
(>>=) :: m a -> (a -> m b) -> m b
-- | Inject a value into the monadic type.
return :: a -> m a
So you see that return is a function that given a value of type a, returns a new value of type m a, where m is some type that is an instance of Monad. Such types include:
Monad []
Monad I0
Monad Maybe
Monad STM
Monad ((->) r)
Monad (Either e)
Monad (ST s)
and many more besides. Instances of 'Monad' should satisfy the following laws:
> return a >>= k == k a
> m >>= return == m
> m >>= (\x -> k x >>= h) == (m >>= k) >>= h
The implementation of a function a -> m a is pretty easy to guess. Here's the definition for the most common monads:
Lists:
return x = [x]
Maybe
return x = Just x
So you see that the return is an overloaded function that "lifts" a value into a monadic wrapper. You can thus use it anywhere you can use its definition. E.g.
Prelude> 1 : return 2
[1,2]
or in the do notion (useful when chaining expressions).
> do v <- return 7 ; return v :: Maybe Int
Just 7
The real reason to use a monadic return is when composing multiple values in some monad:
Prelude> do x <- return 1 ; y <- return 2 ; return (x + y) :: Maybe Int
Just 3
Prelude> do x <- Nothing ; y <- return 2 ; return y
Nothing
In the last statement you see how the chain short-circuited once it hit a zero value for the given monad. In this case Nothing.
Summary: return is an overloaded function that lifts a value into a monadic wrapper. You use it when you need to lift values. It is not a control-flow keyword, as it is in imperative languages.
I suspect that you're misunderstanding what "return" means in the context of a monad in Haskell. return is a function that takes in an a and returns a "wrapped a" -- that is, the simplest possible instance of the monad. In other languages it is often called Unit. It's not the "control flow" return that you see in C-like languages.
So in your example of the Maybe monad, we have return defined as a function that takes in an a and returns a Maybe a:
return :: a -> Maybe a
And what does it do? if you give it x, it gives you back Just x:
return x = Just x
And now you can use return as a shorthand when you need that function, rather than writing out:
\x -> Just x
It's called return because when you're writing out monads in do notation, it looks like what you'd do in a C-like language.
Mike Hartl comment led me to the right direction, although was not so formal imho, so I just post my final understanding what so special about 'return' operator.
Any type class lists operator it supports and there are functions that can work only in this class context (imposed via class constratint symbol =>). So, for example filterM signature
filterM :: Monad m => (a -> m Bool) -> [a] -> m [a]
shows us that it can be used only in monadic context. The magic is that in the body this function is free to use any operator the class has (>>= and return for Monad) and if an instance (for example my MaybeG ) lacks a method (return in my case) then the function can fail. So when the return is there
> filterM (\x -> JustG (x > 0)) [2, 1, 0, -1]
JustG [2,1]
and when it's commented (see my implementation of MaybeG in the question)
> filterM (\x -> JustG (x > 0)) [2, 1, 0, -1]
*** Exception: Monad.hs:3:10-21: No instance nor default method for class operation GHC.Base.return
so imlementation of any operator (return in monad case) is required if one plans to use the instance with functions working with this class (monad in this case) constraint.
I think my initial misunderstanding was due to the fact that most tutorials explains monadic chains without polymorphic (ad hoc) context. This context in my opinion makes monads more powerful and reusable.
I have some confusion with the function monad. The function monad is defined as follow:
instance Monad ((->) r) where
return x = \_ -> x
h >>= f = \w -> f (h w) w
I tried to play around with it by writing a binding operation:
( (*2) >>= (+10) ) 3
(return 3) :: ((->) Int)
But it caused errors. And I also try to rewrite a function AddStuff into the binding operations.
addStuff = do
a <- (*2)
b <- (+10)
return (a+b)
then convert this function into
addStuff' w = (*2) w >>= (\a ->
(+10) w >>= (\b ->
return (a+b) ))
I check the type of the new function as see
addStuff :: (Monad m, Num (m b), Num b) => m b -> m b
Why is that? How can I fix that?
In addStuff' you write (*2) w and (+10) w. Those are equivalent to w*2 and w+10 respectively. So addStuff' is equivalent to this:
addStuff' w = w*2 >>= \a ->
w+10 >>= \b ->
return (a+b)
Writing it this way should make it obvious that here the left operands to >>= are numbers, not functions. That's why the inferred type is telling you that your function only works for numbers that are monads.
When eliminating do notation the left operand to >>= should be exactly the same as the right operand of <-. Also eliminating do notation does not add any arguments to the function. So the correct rewriting would look like this:
addStuff' = (*2) >>= \a ->
(+10) >>= \b ->
return (a+b)
As to why your earlier pieces of code don't work:
( (*2) >>= (+10) ) 3
The operator >>= has type m a -> (a -> m b) -> m b. For simplicity let's assume that all the numbers in this code have type Int, then your left operand has type Int -> Int or m Int if m is (->) Int. So for some type b the right operand should have type Int -> ((->) Int) b or, more readably, Int -> Int -> b. The type it actually has though is Int -> Int. Therefore your expression is ill-typed.
(return 3) :: ((->) Int)
((->) Int) has kind * -> * - the type of a value must have kind *.
Or to approach this differently: return 3 has type m Int for some m (still assuming that all integer literals have type Int for simplicity). So if m is ((->) Int), the type of return 3 will be ((->) Int) Int or Int -> Int, not ((->) Int).
I'm attempting to implement church numerals in Haskell, but I've hit a minor problem. Haskell complains of an infinite type with
Occurs check: cannot construct the infinite type: t = (t -> t1) -> (t1 -> t2) -> t2
when I try and do subtraction. I'm 99% positive that my lambda calculus is valid (although if it isn't, please tell me). What I want to know, is whether there is anything I can do to make haskell work with my functions.
module Church where
type (Church a) = ((a -> a) -> (a -> a))
makeChurch :: Int -> (Church a)
makeChurch 0 = \f -> \x -> x
makeChurch n = \f -> \x -> f (makeChurch (n-1) f x)
numChurch x = (x succ) 0
showChurch x = show $ numChurch x
succChurch = \n -> \f -> \x -> f (n f x)
multChurch = \f2 -> \x2 -> \f1 -> \x1 -> f2 (x2 f1) x1
powerChurch = \exp -> \n -> exp (multChurch n) (makeChurch 1)
predChurch = \n -> \f -> \x -> n (\g -> \h -> h (g f)) (\u -> x) (\u -> u)
subChurch = \m -> \n -> (n predChurch) m
The problem is that predChurch is too polymorphic to be correctly inferred by Hindley-Milner type inference. For example, it is tempting to write:
predChurch :: Church a -> Church a
predChurch = \n -> \f -> \x -> n (\g -> \h -> h (g f)) (\u -> x) (\u -> u)
but this type is not correct. A Church a takes as its first argument an a -> a, but you are passing n a two argument function, clearly a type error.
The problem is that Church a does not correctly characterize a Church numeral. A Church numeral simply represents a number -- what on earth could that type parameter mean? For example:
foo :: Church Int
foo f x = f x `mod` 42
That typechecks, but foo is most certainly not a Church numeral. We need to restrict the type. Church numerals need to work for any a, not just a specific a. The correct definition is:
type Church = forall a. (a -> a) -> (a -> a)
You need to have {-# LANGUAGE RankNTypes #-} at the top of the file to enable types like this.
Now we can give the type signature we expect:
predChurch :: Church -> Church
-- same as before
You must give a type signature here because higher-rank types are not inferrable by Hindley-Milner.
However, when we go to implement subChurch another problem arises:
Couldn't match expected type `Church'
against inferred type `(a -> a) -> a -> a'
I am not 100% sure why this happens, I think the forall is being too liberally unfolded by the typechecker. It doesn't surprise me though; higher rank types can be a bit brittle because of the difficulties they present to a compiler. Besides, we shouldn't be using a type for an abstraction, we should be using a newtype (which gives us more flexibility in definition, helps the compiler with typechecking, and marks the places where we use the implementation of the abstraction):
newtype Church = Church { unChurch :: forall a. (a -> a) -> (a -> a) }
And we have to modify predChurch to roll and unroll as necessary:
predChurch = \n -> Church $
\f -> \x -> unChurch n (\g -> \h -> h (g f)) (\u -> x) (\u -> u)
Same with subChurch:
subChurch = \m -> \n -> unChurch n predChurch m
But we don't need type signatures anymore -- there is enough information in the roll/unroll to infer types again.
I always recommend newtypes when creating a new abstraction. Regular type synonyms are pretty rare in my code.
This definition of predChurch doesn't work in simply typed lambda calculus, only in the untyped version. You can find a version of predChurch that works in Haskell here.
I have encountered the same problem. And I solved it without adding type signature.
Here's the solution, with cons car copied from SICP.
cons x y = \m -> m x y
car z = z (\p q -> p)
cdr z = z (\p q -> q)
next z = cons (cdr z) (succ (cdr z))
pred n = car $ n next (cons undefined zero)
sub m n = n pred m
You can find full source here.
I'm really amazed after writing sub m n = n pred m, and load it in ghci without type error!
Haskell code is so concise! :-)