I am reading the excellent article Understanding map and apply by Scott Wlaschin and running some Haskell code to understand the concepts (Functor, Applicative, ...). I stumbled upon a behaviour I do not understand.
Why evaluating pure add1 prints nothing ? What is the value of the evaluated expression ? Why pure add1 "abc" gives me back the function add1 ?
I understand that pure lifts a value into the elevated world (so called in the article). Since I do not provide a concrete lifted value somewhere or enough type information, the type constraint is general and stays Applicative f. Thus I understand the type of pure add1. But the rest of what's happening here eludes me.
$ stack ghci
GHCi, version 8.8.2
λ: add1 :: Int -> Int ; add1 x = x + 1
λ: :t add1
add1 :: Int -> Int
λ: add1 100
101
λ: :t pure
pure :: Applicative f => a -> f a
λ: pure add1
λ: :t pure add1
pure add1 :: Applicative f => f (Int -> Int)
λ: pure add1 "abc"
<interactive>:8:1: error:
• No instance for (Show (Int -> Int)) arising from a use of ‘print’
(maybe you haven't applied a function to enough arguments?)
• In a stmt of an interactive GHCi command: print it
λ: :t pure add1 "abc"
pure add1 "abc" :: Int -> Int
λ: pure add1 "abc" 100
101
EDIT
I think the two comments by #chi and the answer by #sarah answers the question because it shows the applicative chosen by GHCi to evaluate the expression and that explains the observed behaviour.
Since you are applying the expression pure add1 to the value "abc", the Applicative instance gets picked to be the one for (->) String. In that instance, pure = const, so your final expression is const add1 "abc" which is add1, which has no Show instance!
Related
Reading haskell book about types I want to repeat sample for :t command:
ghci> :t 'a'
'a' :: Char
ghci> :t True
True :: Bool
ghci> :t "HELLO!"
"HELLO!" :: [Char]
ghci> :t (True, 'a')
(True, 'a') :: (Bool, Char)
ghci> :t 4 == 5
4 == 5 :: Bool
Unfortunately I can't install haskell locally, thatswhy I use ideone.com
But I can't understand how create the same sample.
I tried like this:
main = do
putStrLn "Start"
:t 'a'
putStrLn "Finish"
or this:
:t 'a'
or:
putStrLn ("Finish" ++ show :t 'a')
Is there a possibility to show types without installing ghci? Maybe, there is another web fiddle that can do this?
You can use typeOf :: forall a. Typeable a => a -> TypeRep to obtain the TypeRep object. It requires that your type is Typeable, but with the given examples that is the case.
For example:
import Data.Typeable(typeOf)
main = putStrLn ("Finish" ++ show (typeOf 'a'))
This will not print full polymorphic types, since at compile time the types are determined. You thus see the type as is derived by the Haskell compiler.
I have following example with pure function:
Prelude> :t pure ((+1) 1)
pure ((+1) 1) :: (Num a, Applicative f) => f a
What is above the concrete type of f wrapped a?
For example, the f(structure) is here Maybe:
Prelude> pure ((+1) 1) :: Maybe Int
Just 2
and what is the structure of:
pure ((+1) 1)
?
The second example:
Prelude> :t pure ((+1) 1) :: [Int]
pure ((+1) 1) :: [Int] :: [Int]
Why does the GHCi show the type twice, namely :: [Int] :: [Int] not only :: [Int]?
f and a are both type variables. There is no concrete type. It will use whatever type is required by the surrounding context.
When you type :t EXPR, ghci prints the type as EXPR :: TYPE. The first :: [Int] is part of the expression you typed; the second :: [Int] is the type computed by ghci.
I want to make a toy function that produces a Maybe a and then lift show to make it a Maybe String, but the outcome was weird for me:
λ> :t liftM show . Just
liftM show . Just :: Show a1 => a1 -> Maybe String
λ> liftM show . Just $ 10
Just "10"
λ> let f = liftM show . Just
λ> f 10
<interactive>:9:3:
No instance for (Num ()) arising from the literal `10'
Possible fix: add an instance declaration for (Num ())
In the first argument of `f', namely `10'
In the expression: f 10
In an equation for `it': it = f 10
λ> :t f
f :: () -> Maybe String
λ> let g = liftM show . Just :: (Show a) => a -> Maybe String
λ> :t g
g :: () -> Maybe String
λ> let h = liftM show . Just :: Int -> Maybe String
λ> :t h
h :: Int -> Maybe String
I guess it has something to do with type inference, but I really don't know what happened:
where did that mysterious () come from?
why GHCi didn't complain about ambiguousness?
Dum-duuum!
Next victim of the dreaded monomorphism restriction.
What happens is this: for a definition that looks like a "constant variable" (in the sense that other languages might also use, i.e. not of function type), like f = ..., it is assumed that you wish it to actually behave like a constant (CAF, to be precise). That means, it must not be polymorphic, since with parametric polymorphism there's basically an extra implicit argument to the function (the information which type a1 should be).
To achieve this actual-const-ness, ghci defaults this type variable to whatever specific type it deems least inappropriate. Here, the only constraint is Show; the simplest type fulfilling that is ().
The "correct" way of getting around this is to turn off the monomorphism restriction:
Prelude> :set -XNoMonomorphismRestriction
Prelude> :m +Control.Monad
Prelude Control.Monad> let f = liftM show . Just
Prelude Control.Monad> f 10
Just "10"
Alternatively, you can, like in an actual source file you always should, give proper signatures to identifiers in ghci:
Prelude Control.Monad> let g :: Show a => a -> Maybe String; g = liftM show . Just
Prelude Control.Monad> g 10
Just "10"
Doing that only on the RHS of the = doesn't work, since the monomorphism restriction kicks in only after that is resolved and defaults away the variables (unless, as in h, there are no variables in the first place because you gave a monomorphic signature to the RHS).
Still another thing you can do, simply give the function an explicit argument, then the monomorphism restriction doesn't apply at all. I.e., write it non–point-free:
Prelude Control.Monad> let i a = liftM show $ Just a
Prelude Control.Monad> i 10
Just "10"
Here are some pragmas and some imports:
{-# LANGUAGE ScopedTypeVariables #-}
import Control.Monad.ST
import Data.Array.ST
import Data.Array
Now here's my problem. The following code typechecks:
foo :: forall a. a -> [a]
foo x = elems $ runSTArray $ do
newListArray (1,10) (replicate 10 x) :: ST s (STArray s Int a)
However, when I replace the $ with composition:
foo :: forall a. a -> [a]
foo x = elems . runSTArray $ do
newListArray (1,10) (replicate 10 x) :: ST s (STArray s Int a)
I get this error:
Couldn't match expected type `forall s. ST s (STArray s i0 e0)'
with actual type `ST s0 (STArray s0 Int a)'
In the expression:
newListArray (1, 10) (replicate 10 x) :: ST s (STArray s Int a)
In the second argument of `($)', namely
`do { newListArray (1, 10) (replicate 10 x) ::
ST s (STArray s Int a) }'
In the expression:
elems . runSTArray
$ do { newListArray (1, 10) (replicate 10 x) ::
ST s (STArray s Int a) }
What's werid is, if I give the function composition its own name, then it typechecks again:
elemSTArray = elems . runSTArray
foo :: forall a. a -> [a]
foo x = elemSTArray $ do
newListArray (1,10) (replicate 10 x) :: ST s (STArray s Int a)
I'm not sure what's going on here. I would expect the second piece of code to typecheck nicely. And I don't understand why it typechecks again if I give the composed function its own name.
This is a simplified version of some code that I had that broke when upgrading from GHC 6.2 to 7 and I'm trying to understand why this happens now. Thanks for helping!
As you already hint at in the title of your post, the problem has to do with runSTArray having a polymorphic type of rank 2.
runSTArray :: Ix i => (forall s. ST s (STArray s i e)) -> Array i e
With
elems :: Ix i => Array i e -> [e]
and
($) :: (a -> b) -> a -> b
writing runSTArray $ ... means that the type variable a in the type schema of ($) needs to be instantiated with a polymorphic type rather than a monomorphic type. This requires so-called impredicative polymorphism. How GHC implements impredicative polymorphism is explained in the ICFP 2008 paper by Dimitrios Vytiniotis, Stephanie Weirich, and Simon Peyton Jones: FPH : First-class Polymorphism for Haskell. The bottom line is that while FPH often gives you the behaviour that you expect, typeability is sometimes not preserved under simple transformations like the ones you describe in your question: see Section 6.2 of the aforementioned paper.
Stefan beat me to the answer -- the tricky bit is that it's not the $ vs . between elems and runSTArray that's the issue -- it's the $ following runSTArray. Since something $ rankNthing is so common, there's a clever bit (I forget the details) that tries to let you do that as a corner case. But somehow using the composition earlier on prevents this. The location of the issue is demonstrated by the fact that the following will typecheck:
foo x = (elems . runSTArray) (
(newListArray (1,10) (replicate 10 x) :: ST s (STArray s Int String)))
I'm not sure this is a bug per se, but its certainly an unexpected behavior worth creating a ticket about, since there might still be a better algorithm to catch cases like the one you provided.
In ghci:
λ> :t (pure 1)
(pure 1) :: (Applicative f, Num a) => f a
λ> show (pure 1)
<interactive>:1:1:
No instance for (Show (f0 a0))
arising from a use of `show'
Possible fix: add an instance declaration for (Show (f0 a0))
In the expression: show (pure 1)
In an equation for `it': it = show (pure 1)
λ> pure 1
1
Does this mean that ghci execute Applicative and displays the result, just like IO?
Note that pure () and pure (+1) don't print anything.
You get the same behaviour if you use return instead of pure. To find out what to do, ghci must choose a type for the given expression. ghci's defaulting rules are such that absent other constraints, it chooses IO for an Applicative or Monad instance. Thus it interprets pure 1 as an expression of type IO Integer. Expressions of type IO a entered at the prompt are executed and their results are printed, if 1. a has a Show instance and 2. a is not (). Thus entering pure 1 at the prompt results in
v <- return (1 :: Integer)
print v
return v
being executed (and the magic variable it bound to the returned v). For pure (), the special case applies since () is considered uninteresting, thus only return () is executed and it bound to (), for pure (+1), a function is returned, there's no Show instance for functions in scope, so nothing is printed. However,
Prelude Control.Applicative> :m +Text.Show.Functions
Prelude Control.Applicative Text.Show.Functions> pure (+1)
<function>
it :: Integer -> Integer
Prelude Control.Applicative Text.Show.Functions> it 3
4
it :: Integer
with a Show instance for functions in scope, it gets printed (not that it's informative), and the function can then be used (the latter is independent of a Show instance being in scope, of course).