Chapter 6, exercise 7, Haskell from first principles - haskell

For the following code:
module Main where
data EitherOr a b = Hello a | Goodbye b deriving Show
instance (Eq a, Eq b) => Eq (EitherOr a b) where
(==) (Hello x) (Hello x') = x == x'
(==) (Goodbye x) (Goodbye x') = x == x'
(==) _ _ = False
main :: IO ()
main = do
print (Hello 2 == Hello 2)
-- print (Hello 3 == Hello 2)
-- print (Goodbye 3 == Goodbye 3)
-- print (Goodbye 4 == Goodbye 3)
-- print (Hello 3 == Goodbye 3)
executed under runhaskell, i.e., under ghc, I get the following error:
• Ambiguous type variable ‘b0’ arising from a use of ‘==’
prevents the constraint ‘(Eq b0)’ from being solved.
Probable fix: use a type annotation to specify what ‘b0’ should be.
These potential instances exist:
instance Eq Ordering -- Defined in ‘GHC.Classes’
instance Eq Integer
-- Defined in ‘integer-gmp-1.0.2.0:GHC.Integer.Type’
instance (Eq a, Eq b) => Eq (EitherOr a b)
-- Defined at /tmp/runghcXXXX61964-0.hs:5:10. <-- This is because I am using org-mode source blocks
...plus 23 others
...plus 11 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In the first argument of ‘print’, namely ‘(Hello 2 == Hello 2)’
In a stmt of a 'do' block: print (Hello 2 == Hello 2)
In the expression: do print (Hello 2 == Hello 2)
|
12 | print (Hello 2 == Hello 2)
| ^^^^^^^^^^^^^^^^^^
I thought I could give the compiler a type hint by doing
print ((Hello (2 :: Int)) == (Hello (2 :: Int)))
or something similar, but that doesn't seem to be enough. I see that a and b are polymorphic, but I thought the use of == in main might be enough to help the compiler infer types.
Next I loaded the data type and typeclass instance in ghci and explored the types a bit and found that, for instance
λ> :t Hello (2 :: Int)
Hello (2 :: Int) :: EitherOr Int b
As expected. Again in ghci, I do more exploration and see that default types are being used
λ> :t (Hello 2 == Hello 2)
<interactive>:1:2: warning: [-Wtype-defaults]
• Defaulting the following constraints to type ‘Integer’
(Eq a0) arising from a use of ‘==’ at <interactive>:1:2-19
(Num a0) arising from the literal ‘2’ at <interactive>:1:8
• In the expression: (Hello 2 == Hello 2)
<interactive>:1:2: warning: [-Wtype-defaults]
• Defaulting the following constraint to type ‘()’
Eq b0 arising from a use of ‘==’
• In the expression: (Hello 2 == Hello 2)
(Hello 2 == Hello 2) :: Bool
which is what I want, of course.
Then I actually execute the code in ghci and get the right answer with some defaulting going on
λ> Hello 2 == Hello 2
<interactive>:27:1: warning: [-Wtype-defaults]
• Defaulting the following constraints to type ‘Integer’
(Eq a0) arising from a use of ‘==’ at <interactive>:27:1-18
(Num a0) arising from the literal ‘2’ at <interactive>:27:7
• In the expression: Hello 2 == Hello 2
In an equation for ‘it’: it = Hello 2 == Hello 2
<interactive>:27:1: warning: [-Wtype-defaults]
• Defaulting the following constraint to type ‘()’
Eq b0 arising from a use of ‘==’
• In the expression: Hello 2 == Hello 2
In an equation for ‘it’: it = Hello 2 == Hello 2
<interactive>:27:1: warning: [-Wtype-defaults]
• Defaulting the following constraints to type ‘Integer’
(Eq a0) arising from a use of ‘==’ at <interactive>:27:1-18
(Num a0) arising from the literal ‘2’ at <interactive>:27:7
• In the expression: Hello 2 == Hello 2
In an equation for ‘it’: it = Hello 2 == Hello 2
<interactive>:27:1: warning: [-Wtype-defaults]
• Defaulting the following constraint to type ‘()’
Eq b0 arising from a use of ‘==’
• In the expression: Hello 2 == Hello 2
In an equation for ‘it’: it = Hello 2 == Hello 2
True
But the same code executed under runhaskell, i.e., under ghc compilation, fails with the error I first gave. What do I need to learn here?

The type defaulting rules in GHCi are different than those used when compiling a program such as with GHC. When a type is ambiguous you should give an explicit signature such as:
print (Hello 2 == (Hello 2 :: EitherOr Integer ())
In practice this isn't needed too often because the types are implied by other parts of the program. Toy and educational snippets like the above do not have much in the way of context which could add information for the type checker.

Related

Haskell warning

I have written the code (I'm new to haskell, very new) and can't solve the warning.
problem:
funk :: Num a => a -> a
funk a = a + 10
main :: IO()
main = print (funk 10 )
Warning:
Warnings: 1
/home/anmnv/Desktop/qqq.hs: line 4, column 8:
Warning: • Defaulting the following constraints to type ‘Integer’
(Show a0) arising from a use of ‘print’ at qqq.hs:4:8-23
(Num a0) arising from a use of ‘funk’ at qqq.hs:4:15-21
• In the expression: print (funk 10)
In an equation for ‘main’: main = print (funk 10)
It simply says that you did not specify the type for 10. It can strictly speaking by any type that is an member of the Num typeclass, but the compiler uses defaulting rules, and thus picks an Integer.
You can give Haskell a type constraint to determine the type of 10, for example:
funk :: Num a => a -> a
funk = (+ 10)
main :: IO ()
main = print (funk (10 :: Integer))

Haskell read function with no annotation

Does haskell read function implicitly converts a data type into another?
import IO
main = do
putStrLn "Enter an interger: "
num <- getLine
putStr "Value + 3 is "
putStrLn (show((read num) + 3))
So, haskell interpreter automatically changes num's data type from string to int to handle '+ 3'?
read has type Read a => String -> a, which means that it can convert a String into any type that is an instance of the Read type class. Which type it will use depends on the surrounding code. In this case you write read num + 3. The + operator is also overloaded to work for any type that is an instance of Num, so the type of read num + 3 is (Read a, Num a) => a. Haskell has a mechanism that chooses a default type whenever the Num type class remains in the final type of an expression. In this case it defaults to Integer, so the final type is Integer.
You can see this in action by enabling the -Wtype-defaults warning which is also included in -Wall:
Test.hs:5:15: warning: [-Wtype-defaults]
• Defaulting the following constraints to type ‘Integer’
(Show a0) arising from a use of ‘show’ at Test.hs:5:15-34
(Num a0) arising from a use of ‘+’ at Test.hs:5:20-33
(Read a0) arising from a use of ‘read’ at Test.hs:5:21-28
• In the first argument of ‘putStrLn’, namely
‘(show ((read num) + 3))’
In a stmt of a 'do' block: putStrLn (show ((read num) + 3))
In the expression:
do putStrLn "Enter an interger: "
num <- getLine
putStr "Value + 3 is "
putStrLn (show ((read num) + 3))
|
5 | putStrLn (show((read num) + 3))
|
Here you are using
show :: Show a => a -> String
read :: Read a => String -> a
(+) :: Num a => a -> a -> a
3 :: Num a => a
on the same type a. So, Haskell searches for a type a satisfying Show a, Read a, Num a.
In principle, this would be rejected since the type is ambiguous, but Haskell mandates a special rules for Num, causing a to be defaulted, usually to Integer. Since that satisfies also Show and Read, the program type-checks.

To generate a random number by using time

I would like to generate a number by using Data.Time.Clock.POSIT
test' = do
y <- getPOSIXTime
let w = (tail (take 3 (reverse(show y))))
return w
test2 = do
getseed <- test'
let x = read (getseed)
putStrLn (show(x))
So I use getPOSIXTime to get time with the nanosecond, so I convert it into a string and take the first 3 digits and then convert them back to Int. However, it gives me error like this:
test.hs:156:14: error:
• Ambiguous type variable ‘a0’ arising from a use of ‘read’
prevents the constraint ‘(Read a0)’ from being solved.
Relevant bindings include x :: a0 (bound at test.hs:156:10)
Probable fix: use a type annotation to specify what ‘a0’ should be.
These potential instances exist:
instance Read GeneralCategory -- Defined in ‘GHC.Read’
instance Read Ordering -- Defined in ‘GHC.Read’
instance Read Integer -- Defined in ‘GHC.Read’
...plus 23 others
...plus 12 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In the expression: read (getseed)
In an equation for ‘x’: x = read (getseed)
In the expression:
do getseed <- test'
let x = read (getseed)
putStrLn (show (x))
|
156 | let x = read (getseed)
| ^^^^^^^^^^^^^^
test.hs:157:16: error:
• Ambiguous type variable ‘a0’ arising from a use of ‘show’
prevents the constraint ‘(Show a0)’ from being solved.
Relevant bindings include x :: a0 (bound at test.hs:156:10)
Probable fix: use a type annotation to specify what ‘a0’ should be.
These potential instances exist:
instance Show GeneralCategory -- Defined in ‘GHC.Unicode’
instance Show Ordering -- Defined in ‘GHC.Show’
instance Show Integer -- Defined in ‘GHC.Show’
...plus 23 others
...plus 27 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In the first argument of ‘putStrLn’, namely ‘(show (x))’
In a stmt of a 'do' block: putStrLn (show (x))
In the expression:
do getseed <- test'
let x = read (getseed)
putStrLn (show (x))
|
157 | putStrLn (show(x))
| ^^^^^^^
any help would be appreciated!!

Print out a char in main method

I have two modules defined as follows:
Foo.hs
module Foo
where
class F t where
c :: t -> Char
instance F Double where
c s = 'x'
Main.hs
import Foo
main :: IO ()
main = do
print $ (c 2.0)
When I compile these two modules I get this error:
ghc Foo.hs Main.hs
[1 of 2] Compiling Foo ( Foo.hs, Foo.o )
[2 of 2] Compiling Main ( Main.hs, Main.o )
Main.hs:6:12: error:
• Ambiguous type variable ‘t0’ arising from a use of ‘c’
prevents the constraint ‘(F t0)’ from being solved.
Probable fix: use a type annotation to specify what ‘t0’ should be.
These potential instance exist:
instance [safe] F Double -- Defined in ‘Foo’
• In the second argument of ‘($)’, namely ‘(c 2.0)’
In a stmt of a 'do' block: print $ (c 2.0)
In the expression: do { print $ (c 2.0) }
Main.hs:6:14: error:
• Ambiguous type variable ‘t0’ arising from the literal ‘2.0’
prevents the constraint ‘(Fractional t0)’ from being solved.
Probable fix: use a type annotation to specify what ‘t0’ should be.
These potential instances exist:
instance Fractional Double -- Defined in ‘GHC.Float’
instance Fractional Float -- Defined in ‘GHC.Float’
...plus one instance involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In the first argument of ‘c’, namely ‘2.0’
In the second argument of ‘($)’, namely ‘(c 2.0)’
In a stmt of a 'do' block: print $ (c 2.0)
How do I fix this so it prints out 'x'?
You should just rename call to c.
EDIT: Try annotating 2.0 as Double:
print $ c (2.0 :: Double)
GHC doesn't know which type to use for 2.0, it could be any Fractional type. To fix this we force 2.0 to be of type Double by explicitly marking its type.

How and why is [1 .. 0] different from [1 .. -1] in Haskell?

I have defined the following function
let repl x n = [x | _ <- [1..n]]
which imitates the built-in replicate function.
While experimenting with it, I noticed a strange thing: repl 10 0 evaluates to [], while repl 10 -1 produces an error:
No instance for (Show (t10 -> [t0])) arising from a use of ‘print’
In a stmt of an interactive GHCi command: print it
On the other hand, both [1 .. 0] and [1 .. -1] evaluate to [] without producing any errors.
Moreover, both [42 | _ <- [1 .. 0]] and [42 | _ <- [1 .. -1]] evaluate to [] without errors.
So why does my function call result in an error where the explicit substitution doesn't? And more importantly, where does the apparent difference between [1 .. 0] and [1 .. -1] stem from?
And a final question: when I write:
repl 42 -1
the error is exactly the same as with repl 10 -1, i.e. it still has the (Show (t10 -> [t0])) bit in it. I was expecting it to have something like ((Show (t42 -> [t0]))). What's this 10?
Other answers have pointed out that you need to wrap -1 in parentheses. This is an odd corner of the Haskell 98 spec that jumps out to bite unexpectedly. It's not the case that you can never write a negative number without parentheses: -1 * 5 is fine. It's just that the unary prefix operator doesn't have higher precedence than the binary infix operator, so a - is frequently parsed as the latter. Whitespace around operators is not significant in Haskell.
And the incomprehensible typeclass error doesn't help. Incidentally, t10 and t0 are just placeholder type variables made up by the compiler; I don't think it has anything to do with the actual numeric literals you use. And informally, errors like Could not deduce (Num (a0 -> t)) usually indicate to me that a function is applied to too few arguments.
Alternatively, the (undocumented?) NegativeLiterals language extension in GHC 7.8 changes the meaning of -1 to address this problem.
> :set -XNegativeLiterals
> :t repl 10 -1
repl 10 -1 :: Num t => [t]
You have not included the full error message in your question, and if you had, you'd see that repl 10 -1 is parsed as (repl 10) - (1) which is not what you intended.
You'd get the same error with repl 10 +1.
You can often find clues as to how a program code is parsed, by looking closely into the error message. There's no harm in overusing parentheses, while you learn, either.
The program:
repl x n = [x | _ <- [1..n]] -- line 1
main = print (repl 10 -1) -- line 3
The message:
prog.hs:3:8:
No instance for (Show (t1 -> [t0])) arising from a use of `print'
Possible fix: add an instance declaration for (Show (t1 -> [t0]))
In the expression: print (repl 10 - 1)
In an equation for `main': main = print (repl 10 - 1)
prog.hs:3:15:
No instance for (Num t1) arising from a use of `repl'
The type variable `t1' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance Num Double -- Defined in `GHC.Float'
instance Num Float -- Defined in `GHC.Float'
instance Integral a => Num (GHC.Real.Ratio a)
-- Defined in `GHC.Real'
...plus three others
In the first argument of `(-)', namely `repl 10' --------- NB!
In the first argument of `print', namely `(repl 10 - 1)'
In the expression: print (repl 10 - 1)
prog.hs:3:20:
No instance for (Num t0) arising from the literal `10'
The type variable `t0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance Num Double -- Defined in `GHC.Float'
instance Num Float -- Defined in `GHC.Float'
instance Integral a => Num (GHC.Real.Ratio a)
-- Defined in `GHC.Real'
...plus three others
In the first argument of `repl', namely `10'
In the first argument of `(-)', namely `repl 10' --------- NB!
In the first argument of `print', namely `(repl 10 - 1)'
prog.hs:3:23:
No instance for (Num (t1 -> [t0])) arising from a use of `-'
Possible fix: add an instance declaration for (Num (t1 -> [t0]))
In the first argument of `print', namely `(repl 10 - 1)'
In the expression: print (repl 10 - 1)
In an equation for `main': main = print (repl 10 - 1)
Did you try [1..(-1)]? In Haskell, you cannot write negative numbers like -1 directly. You need to put them in parentheses. The reason is that Haskell doesn't have prefix unary operators because operators in Haskell are always infix. Hence -1 is parsed as [operator (-)] [numeric 1] and not [numeric -1].
This is what causes the problem. To avoid this problem, negative numbers must always be put in parentheses. This ensures that (-1) is parsed as [numeric -1]. It's one of the few corner cases which gives migraines to newcomers in Haskell.

Resources