How does Haskell's * work? Does it create a series of + operators, or does it do something else?
This is the Num type class
type Num :: Type -> Constraint
class Num a where
(+) :: a -> a -> a
(*) :: a -> a -> a
-- .. I'm omitting the other methods
This is how Num is defined for Int (src)
instance Num Int where
(+) :: Int -> Int -> Int
I# x + I# y = I# (x +# y)
(*) :: Int -> Int -> Int
I# x * I# y = I# (x *# y)
-- ..
This is how it's defined for Float (src)
instance Num Float where
(+) :: Float -> Float -> Float
F# x + F# y = F# (plusFloat# x y)
(*) :: Float -> Float -> Float
F# x * F# y = F# (timesFloat# x y)
Maybe not enlightening but you can see that (for those instances) they are defined in terms of primitive operations like (+#) or timesFloat#. If you define your own number you can define multiplication in terms of repeated addition but the operations are not fundamentally defined that way.
type N :: Type
data N = O | S N
instance Num N where
(+) :: N -> N -> N
O + m = m
S n + m = S (n + m)
(*) :: N -> N -> N
O * _ = O
S n * m = m + (n * m)
You can define a "default" multiplication function that is defined in terms of repeated additions
-- >> timesViaPlus #Int #Int 10 20
-- 200
-- >> timesViaPlus #Integer #Integer 10 20
-- 200
timesViaPlus :: Integral n => Num m => n -> m -> m
timesViaPlus n m = sum (fromIntegral n `replicate` m)
or you could specialize it to N and use it to define (*) #N.
replicateN :: N -> a -> [a]
replicateN O _ = []
replicateN (S n) a = a : replicateN n a
timesViaPlusN :: Num n => N -> n -> n
timesViaPlusN n m = sum (n `replicateN` m)
instance Num N where
(+) :: N -> N -> N
O + m = m
S n + m = S (n + m)
(*) :: N -> N -> N
(*) = timesViaPlusN
Related
I want to negate a function in the if clause of another function like bellow:
isBig :: Integer -> Bool
isBig n = n > 9999
function :: Integer -> Integer
function n =
if not isBig n then ... else ...
It complies when it's just 'if isBig n then else' but I'm not sure why it doesn't work for 'not isBig' as I get this error:
*Couldn't match expected type Bool' with actual type Integer -> Bool'
Many thanks in advance.
You want not (isBig n). not isBig n tries to pass two arguments to not, both isBig and n. isBig is an Integer -> Bool but a Bool is expected, hence the error.
In general, function application in Haskell is left-associative, meaning that an expression like this:
f 2 3 5
Is parsed like this:
(((f 2) 3) 5)
Likewise, the arrows in function types are right-associative, so for example if we had this definition for f:
f :: Int -> Int -> Int -> Int
f x y z = x * y + z
That type signature is the same as:
f :: Int -> (Int -> (Int -> Int))
So it looks like this as you apply more arguments:
f :: Int -> (Int -> (Int -> Int))
(f 2) :: (Int -> (Int -> Int))
((f 2) 3) :: (Int -> Int)
(((f 2) 3) 5 :: Int
==
f :: Int -> Int -> Int -> Int
f 2 :: Int -> Int -> Int
f 2 3 :: Int -> Int
f 2 3 5 :: Int
When you’re applying a chain of functions to an argument, you end up with parentheses associating to the right:
f (g (h x))
In this case it’s common to use the $ operator, which is right-associative and has low precedence, just to reduce the nesting of brackets:
f $ g $ h x
And you can do so in your case: not $ isBig n
You can also use composition to factor out the chain of functions and apply it to different arguments elsewhere:
fgh = f . g . h
fgh x
==
(f . g . h) x
==
f (g (h x))
isNotBig = not . isBig
isNotBig n
==
(not . isBig) n
==
not (isBig n)
Given binary natural numbers, with a zero case a "twice" case and a "twice plus one" case. How can one express addition using primitive recursion (using only the function foldBNat)?
-- zero | n * 2 | n * 2 + 1
data BNat = Z | T BNat | TI BNat
deriving (Show)
foldBNat :: BNat -> t -> (BNat -> t -> t) -> (BNat -> t -> t) -> t
foldBNat n z t ti =
case n of
Z -> z
T m -> t m (foldBNat m z t ti)
TI m -> ti m (foldBNat m z t ti)
div2 :: BNat -> BNat
div2 n = foldBNat n Z (\m _ -> m) (\m _ -> m)
pred :: BNat -> BNat
pred n = foldBNat n Z (\_ r -> TI r) (\m _ -> T m)
succ :: BNat -> BNat
succ n = foldBNat n (TI Z) (\m _ -> TI m) (\_ r -> T r)
Idea: To compute a + b, we need to increment b a times. So:
0 + b = b
1 + b = succ b
2 + b = succ (succ b)
3 + b = succ (succ (succ b))
...
We might start out by writing
plus a b = foldBNat a b (\m r -> ...
But here we get stuck: m represents half of a (since a = T m here, i.e. a = 2 * m) and r is the result of incrementing b m times (i.e. m + b). There's nothing useful we can do with that. What we want is a + b = 2*m + b, which we can't directly obtain from m + b. Applying T would only give us 2 * (m + b) = 2*m + 2*b, which is too big, and according to the rules we can't directly recurse on plus to compute m + (m + b) = 2*m + b.
What we need is a more direct way of manipulating the number of succ operations.
Idea: Don't compute a number directly; instead compute a function (that increments its argument a certain number of times). So:
incBy 0 = id
incBy 1 = succ
incBy 2 = succ . succ
incBy 3 = succ . succ . succ
...
We can implement that directly:
incBy :: BNat -> (BNat -> BNat)
incBy n = foldBNat n id (\_ r -> r . r) (\_ r -> succ . r . r)
Here r . r gives us a function that increments a number twice as often as r does (by applying r twice).
Now we can simply define addition as:
plus :: BNat -> BNat -> BNat
plus n m = (incBy n) m
(which happens to be redundant because plus = incBy).
Prelude> let [x,y] = [3,4] in x*x+y*y
25
Prelude> let x:[y] = [3,4] in x*x + y*y
25
Prelude> let x:y = 3:4 in x*x+y*y
interactive:6:5: error:
* Non type-variable argument in the constraint: Num [a]
(Use FlexibleContexts to permit this)
* When checking the inferred type
x :: forall a. (Num a, Num [a]) => a
In the expression: let x : y = 3 : 4 in x * x + y * y
In an equation for `it': it = let x : y = 3 : 4 in x * x + y * y
Can someone explain what is happening in the first two statements and why is there an error for the third let ... in .. statement.
In the third example, the right-hand-side of the let assignment is: 3:4. The : (cons) operator has the type signature a -> [a] -> [a]: it takes a value on its left side, and a list of that type of value on the right side. In this case, 3 is an a, but 4 is not a list of a ([a]); it is also an a. This is invalid.
Given the form of your exercise so far, there are two ways that you can fix this expression: with 3:[4] or with 3:4:[].
If you tried running your code now, you would see that it fails on x * x + y * y. This is because your pattern-match assigns x to 3, and y to [4] (a singleton list). A list cannot be multiplied by itself, nor can it be added to a number. So once more, we use the solution for the right-hand-side, on the left-hand-side:
let x:y:[] = 3:4:[]
in x * x + y * y
If we add a few too many type annotations, you can hopefully see where things are going wrong:
-- These work fine
-- let [x, y] = [3, 4] in ...
example1 = let [(x :: a), (y :: a)] :: [a]
= [(3 :: a), (4 :: a)] :: [a]
in x * x + y * y
-- let x:[y] = [3, 4] in ...
example2 = let ((x :: a) : ([(y :: a)] :: [a])) :: [a]
in x * x + y * y
-- This is the incorrect implementation
-- let x:y = 3:4 in ...
example3 :: (Num a) => a
example3 = let (x :: a) : (y :: [a]) -- (:) :: a -> [a] -> [a]
= (3 :: a) : (4 :: a) -- 4 :: a is invalid here: require [a]
in (x :: a) * (x :: a)
+ (y :: [a]) * (y :: [a]) -- Trying to multiply two lists
-- This is the fixed implementation
-- let x:y:[] = 3:4:[] in ...
example3' :: (Num a) => a
example3' = let ((x :: a) : (y :: a) : ([] :: [a])) :: [a]
= ((3 :: a) : (4 :: a) : ([] :: [a])) :: [a]
in x * x + y * y
I tried all possible type declarations but I can't make this code even compile. The trick is in handling types for division. I tried Num a, Fractional a, Float a etc.
cube x = x * x * x
sum' term a next b =
if a > b
then 0
else term a + sum' term (next a) next b
integral f a b n = (h / 3) * (sum' term 0 succ n) where
h = (b - a) / n
y k = f $ a + (k * h)
term k
| k == 0 || k == n = y k
| odd k = 4 * y k
| even k = 2 * y k
main = do
print $ integral cube 0 1 100 -- 0.25
print $ (\x -> 3 * x * x) 1 3 100 -- 26
I isolated problem by deleting (/) function. This code compiles without any type declaration at all:
cube x = x * x * x
sum' term a next b =
if a > b
then 0
else term a + sum' term (next a) next b
integral f a b n = (sum' term 0 succ n) where
h = (b - a)
y k = f $ a + (k * h)
term k
| k == 0 || k == n = y k
| odd k = 4 * y k
| even k = 2 * y k
main = do
print $ integral cube 0 1 100
Another question is how to debug cases like this? Haskell's error messages doesn't help much, it's kind of hard to understand something like The type variable a0 is ambiguous or Could not deduce (a1 ~ a).
P. S. It's ex. 1.29 from SICP.
Update
Final answer is:
cube :: Num a => a -> a
cube x = x * x * x
sum' :: (Int -> Double) -> Int -> (Int -> Int) -> Int -> Double
sum' term a next b =
if a > b
then 0
else term a + sum' term (next a) next b
integral :: (Double -> Double) -> Double -> Double -> Int -> Double
integral f a b n = (h / 3) * sum' term 0 (+1) n where
h = (b - a) / n' where n' = fromIntegral n
y k = f $ a + (k * h)
term k
| k == 0 || k == n = y k'
| odd k = 4 * y k'
| even k = 2 * y k'
where k' = fromIntegral k
main = do
print $ integral cube 0 1 100 -- 0.25
print $ integral cube 0 1 1000 -- 0.25
print $ integral (\x -> 3 * x * x) 1 3 100 -- 26
/ is only used for types that are instances of Fractional, for Integral types use quot. You can use quot as an infix operator using backticks:
h = (b - a) `quot` n
The types of the two are
(/) :: Fractional a => a -> a -> a
quot :: Integral a => a -> a -> a
There are no types that are instances of both Fractional and Integral, which is why none of the type signatures would work. Unfortunately GHC doesn't know that it's impossible for a type to be an instance of both classes, so the error messages are not very intuitive. You get used to the style of GHC error messages though, and the detail they give helps a lot.
Also, as was suggested in the comments, I completely agree that all top level definitions should be given type signatures (including main). It makes error messages a lot easier to read.
Edit: Based on the comments below, it looks like what you want is something more like this (type signature-wise)
cube :: Num a => a -> a
sum' :: (Int -> Double) -> Int -> (Int -> Int) -> Int -> Double
integral :: (Double -> Double) -> Double -> Double -> Int -> Double
You will need to use fromIntegral to convert from Int to Double in h and in k. The type errors should be at least a bit more readable with these type signatures though.
Today I found this post on Quora, which claimed that
factorial(n) = def $ do
assert (n<=0) "Negative factorial"
ret <- var 1
i <- var n
while i $ do
ret *= i
i -= 1
return ret
could be correct Haskell code. I got curious, and ended up with
factorial :: Integer -> Integer
factorial n = def $ do
assert (n >= 0) "Negative factorial"
ret <- var 1
i <- var n
while i $ do
ret *= i
i -= 1
return ret
using var = newSTRef, canonical definitions for def, assert and while, and
a *= b = readSTRef b >>= \b -> modifySTRef a ((*) b)
a -= b = modifySTRef a ((+) (negate b))
However, (*=) and (-=) have different types:
(-=) :: Num a => STRef s a -> a -> ST s ()
(*=) :: Num a => STRef s a -> STRef s a -> ST s ()
So ret -= i wouldn't work. I've tried to create a fitting type class for this:
class (Monad m) => NumMod l r m where
(+=) :: l -> r -> m ()
(-=) :: l -> r -> m ()
(*=) :: l -> r -> m ()
instance Num a => NumMod (STRef s a) (STRef s a) (ST s) where
a += b = readSTRef b >>= \b -> modifySTRef a ((+) b)
a -= b = readSTRef b >>= \b -> modifySTRef a ((+) (negate b))
a *= b = readSTRef b >>= \b -> modifySTRef a ((*) b)
instance (Num a) => NumMod (STRef s a) a (ST s) where
a += b = modifySTRef a ((+) (b))
a -= b = modifySTRef a ((+) (negate b))
a *= b = modifySTRef a ((*) (b))
That actually works, but only as long as factorial returns an Integer. As soon as I change the return type to something else it fails. I've tried to create another instance
instance (Num a, Integral b) => NumMod (STRef s a) b (ST s) where
a += b = modifySTRef a ((+) (fromIntegral $ b))
a -= b = modifySTRef a ((+) (negate . fromIntegral $ b))
a *= b = modifySTRef a ((*) (fromIntegral b))
which fails due to overlapping instances.
Is it actually possible to create a fitting typeclass and instances to get the factorial running for any Integral a? Or will this problem always occur?
The idea
Idea is simple: wrap STRef s a in a new data type and make it an instance of Num.
Solution
First, we'll need only one pragma:
{-# LANGUAGE RankNTypes #-}
import Data.STRef (STRef, newSTRef, readSTRef, modifySTRef)
import Control.Monad (when)
import Control.Monad.ST (ST, runST)
Wrapper for STRef:
data MyRef s a
= MySTRef (STRef s a) -- reference (can modify)
| MyVal a -- pure value (modifications are ignored)
instance Num a => Num (MyRef s a) where
fromInteger = MyVal . fromInteger
A few helpers for MyRef to resemble STRef functions:
newMyRef :: a -> ST s (MyRef s a)
newMyRef x = do
ref <- newSTRef x
return (MySTRef ref)
readMyRef :: MyRef s a -> ST s a
readMyRef (MySTRef x) = readSTRef x
readMyRef (MyVal x) = return x
I'd like to implement -= and *= using a bit more general alter helper:
alter :: (a -> a -> a) -> MyRef s a -> MyRef s a -> ST s ()
alter f (MySTRef x) (MySTRef y) = readSTRef y >>= modifySTRef x . flip f
alter f (MySTRef x) (MyVal y) = modifySTRef x (flip f y)
alter _ _ _ = return ()
(-=) :: Num a => MyRef s a -> MyRef s a -> ST s ()
(-=) = alter (-)
(*=) :: Num a => MyRef s a -> MyRef s a -> ST s ()
(*=) = alter (*)
Other functions are almost unchanged:
var :: a -> ST s (MyRef s a)
var = newMyRef
def :: (forall s. ST s (MyRef s a)) -> a
def m = runST $ m >>= readMyRef
while :: (Num a, Ord a) => MyRef s a -> ST s () -> ST s ()
while i m = go
where
go = do
n <- readMyRef i
when (n > 0) $ m >> go
assert :: Monad m => Bool -> String -> m ()
assert b str = when (not b) $ error str
factorial :: Integral a => a -> a
factorial n = def $ do
assert (n >= 0) "Negative factorial"
ret <- var 1
i <- var n
while i $ do
ret *= i
i -= 1
return ret
main :: IO ()
main = print . factorial $ 1000
Discussion
Making Num instances like this feels a bit hacky, but we don't have FromInteger type class in Haskell, so I guess it's OK.
Another itchy thing is 3 *= 10 which is return (). I think it is possible to use phantom type to indicate whether MyRef is ST or pure and allow only ST on the LHS of alter.