How is Ratio implemented in Haskell? - haskell

This is something I have been confused about for a while and I am not sure how I can learn more about it. Let's say I have the following program:
main :: IO ()
main = do
x <- liftM read getLine
y <- liftM read getLine
print (x % y)
If I run this with the input 6 and 2, it will print 3 % 1.
At what point does the simplification happen (namely the division by the gcd)? Is it implemented in show? If so, then is the underlying representation of the rational still 6 % 2? If not, then does (%) do the simplification? I was under the impression that (%) is a data constructor, so how would a data constructor do anything more than "construct"? More importantly, how would I actually go about doing similar things with my own data constructors?
I appreciate any help on the topic.

Ratio is actually implemented in GHC.Real (on GHC, obviously), and is defined as
data Ratio a = !a :% !a deriving (Eq)
The bangs are just there for strictness. As you can see, the function % is not a data constructor, but :% is. Since you aren't supposed to construct a Ratio directly, you use the % function, which calls reduce.
reduce :: (Integral a) => a -> a -> Ratio a
{-# SPECIALISE reduce :: Integer -> Integer -> Rational #-}
reduce _ 0 = ratioZeroDenominatorError
reduce x y = (x `quot` d) :% (y `quot` d)
where d = gcd x y
(%) :: (Integral a) => a -> a -> Ratio a
x % y = reduce (x * signum y) (abs y)
The rule is that if an operator starts with a colon :, then it is a constructor, otherwise it is just a normal operator. In fact, this is part of the Haskell standard, all type operators must have a colon as their first character.

You can just look at the source to see for yourself:
instance (Integral a) => Num (Ratio a) where
(x:%y) + (x':%y') = reduce (x*y' + x'*y) (y*y')
(x:%y) - (x':%y') = reduce (x*y' - x'*y) (y*y')
(x:%y) * (x':%y') = reduce (x * x') (y * y')
negate (x:%y) = (-x) :% y
abs (x:%y) = abs x :% y
signum (x:%_) = signum x :% 1
fromInteger x = fromInteger x :% 1
reduce :: (Integral a) => a -> a -> Ratio a
reduce _ 0 = ratioZeroDenominatorError
reduce x y = (x `quot` d) :% (y `quot` d)
where d = gcd x y

Related

(Haskell) How to convert from Ratio Integer to Ratio Rational?

How does addition of two different ratios work? For instance, ratio integer and ratio rationals don't seem to get added. I tried evaluating the continued fraction for a given list.
Here's the code :
import Data.Ratio
f :: [Integer] -> Rational
f(x:xs)
| (null xs == True) = x
| otherwise = x + (1 % f xs)
What is the correct version of the code supposed to be? Since f yields a Ratio Rational, I feel that x, if type-casted to a Ratio rational number, will suffice.
No type conversion needed, use proper division between rationals.
import Data.Ratio
f :: [Integer] -> Rational
f [] = error "empty list"
f [x] = x % 1
f (x:xs#(_:_)) = x % 1 + 1 / f xs
Here, x % 1 makes x into a Rational (ok, that's conversion, if you want). We could also have used fromInteger, I think.
Then, between Rational values, we do not use % which produces a weird Ratio Rational, but we exploit / which produces a Rational instead.
Converting x to a Rational will not be sufficient here. Since you here write 1 % f xs. The type of (%) is (%) :: Integral a => a -> a -> Ratio a, and since f xs is a Rational, and Rational is not an instance of Integral, we thus need to fix a second issue.
It is however not that hard. We can for example make a function that calculates the inverse:
inverseR :: Integral a => Ratio a -> Ratio a
inverseR r = denominator r % numerator r
Since Ratio a is an instance of Num given a is an instance of Integral, we can use fromInteger :: Num a => Integer -> a:
f :: [Integer] -> Rational
f [x] = fromInteger x
f (x:xs) = fromInteger x + inverseR (f xs)
For example:
Prelude Data.Ratio> f [1,4,2,5]
60 % 49
Since 1 + 1/(4 + 1/(2 + 1/5)) = 1 + 1/(4 + 1/(11/5)) = 1 + 1/(4 + 5/11) = 1 + 1/(49/11) = 1 + 11/49 = 60 / 49.
We can further improve this by:
using fromIntegral :: (Integral a, Num b) => a -> b to convert any integral to a Ratio; and
by using (/) :: Fractional a => a -> a -> a.
We thus can generalize this to a function:
f :: (Integral a, Fractional b) => [a] -> b
f [x] = fromIntegral x
f (x:xs) = fromIntegral x + 1 / f xs
Which yields the same value:
Prelude Data.Ratio> f [1,4,2,5] :: Rational
60 % 49
We can use a foldr pattern, and avoid the explicit recursion:
f :: (Integral a, Fractional b) => [a] -> b
f = foldr1 (\x -> (x +) . (1 /)) . map fromIntegral

Function Type Restrictions

Is it generally preferable to have the strictest or loosest type definition for a function? What are the pros and cons of each approach? I found that when I rewrote my pearson correlation code using strictly doubles, it was easier for me to write, follow, and reason about (this could just be inexperience). But I can also see how having a more broad type definition would make the functions more generally applicable. Would stricter type definitions be characterized as a form of tech debt?
With Typeclasses:
import Data.List
mean :: Fractional a => [a] -> a
mean xs = s / n
where
(s , n) = foldl' k (0,0) xs
k (s, n) x = s `seq` n `seq` (s + x, n + 1)
covariance :: Fractional a => [a] -> [a] -> a
covariance xs ys = mean productXY
where
productXY = zipWith (*) [x - mx | x <- xs] [y - my | y <- ys]
mx = mean xs
my = mean ys
stddev :: Floating a => [a] -> a
stddev xs = sqrt (covariance xs xs)
pearson :: RealFloat a => [a] -> [a] -> a
pearson x y = fifthRound $ covariance x y / (stddev x * stddev y)
pearsonMatrix :: RealFloat a => [[a]] -> [[a]]
pearsonMatrix (x:xs) = [pearson x y | y <- x:xs]:(pearsonMatrix xs)
pearsonMatrix [] = []
fifthRound :: RealFrac a => a -> a
fifthRound x = (/100000) $ fromIntegral $ round (x * 100000)
With Doubles:
import Data.List
mean :: [Double] -> Double
mean xs = s / n
where
(s , n) = foldl' k (0,0) xs
k (s, n) x = s `seq` n `seq` (s + x, n + 1)
covariance :: [Double] -> [Double] -> Double
covariance xs ys = mean productXY
where
productXY = zipWith (*) [x - mx | x <- xs] [y - my | y <- ys]
mx = mean xs
my = mean ys
stddev :: [Double] -> Double
stddev xs = sqrt (covariance xs xs)
pearson :: [Double] -> [Double] -> Double
pearson x y = fifthRound (covariance x y / (stddev x * stddev y))
pearsonMatrix :: [[Double]] -> [[Double]]
pearsonMatrix (x:xs) = [pearson x y | y <- x:xs]:(pearsonMatrix xs)
pearsonMatrix [] = []
fifthRound :: Double -> Double
fifthRound x = (/100000) $ fromIntegral $ round (x * 100000)
Readability is a matter of opinion. In general, I find that more general type signatures are more readable because there are fewer possible definitions (sometimes there is even only one non-diverging definition). For example, seeing that mean only has a Fractional constraint immediately limits the operations being performed in that function (compared to the Double version which could be performing sqrt operations for all I know). Of course, generalizing types is not always more readable. (And just for fun)
The main disadvantage of having more general versions of functions is that they may remain unoptimized at runtime so that Double's dictionary of the Floating functions has to be passed to mean every time it is called.
You can have the best of all worlds by adding a SPECIALIZE pragma. This tells the compiler to basically duplicate your function code with some of the type variables instantiated. If you know you are going to be calling your mean function pretty much only with Double, then this is what I would do
{-# SPECIALIZE mean :: [Double] -> Double #-}
mean :: Fractional a => [a] -> a
mean xs = s / n
where
(s , n) = foldl' k (0,0) xs
k (s, n) x = s `seq` n `seq` (s + x, n + 1)
And you get to see the specialized version of the signature in your code too! Yay!

Why does Haskell want this function's argument to have the type classes (RealFrac x, Integral x) when it only needs to be Integral x?

I'm trying to write some code that does a complete factorization of an integer by trial division. This code seems like it ought to work:
findAFact :: Integral x => x -> x
findAFact x = searchInts [2, 3..] x where
searchInts (int:ints) div
| div `mod` int == 0 = int
| otherwise = searchInts ints div
completeFacts :: Integral x => x -> [x]
completeFacts x = tryForFact [] x where
tryForFact fs x = if x == 1
then fs
else let fact = findAFact x
in tryForFact (fact:fs) (floor ((fromIntegral x) / fact))
but if I try to compile this I get the following error:
Could not deduce (RealFrac x) arising from a use of 'tryForFact'
from the context (Integral x)
bound by the type signature for
completeFacts :: Integral x => x -> [x]
at 5.hs:26:18-39
Possible fix:
add (RealFrac x) to the context of
the type signature for completeFacts :: Integral x => x -> [x]
In the expression: tryForFact [] x
In an equation for 'completeFacts':
completeFacts x
= tryForFact [] x
where
tryForFact fs x
= if x == 1 then
fs
else
let ... in tryForFact (fact : fs) (floor ((fromIntegral x) / fact))
If I remove the type signature from completeFacts and try loading it into GHCI, the interpreter loads the file and supplies the type signature (RealFrac x, Integral x ) => x -> [x] for completeFacts, but then complains when I try to use completeFacts that there's no way to show it because its type is ambiguous in the context of show. That makes sense to me because it seems like there would be a clear way to display x as a RealFrac or an Integral, but not both.
This seems to be the offending code:
...
in tryForFact (fact:fs) (floor ((fromIntegral x) / fact))
I'm confused because I'd imagine passing x through fromIntegral and then passing the result of the division into floor would give me an Integral back. I don't see why Haskell still thinks x also needs to have the type class RealFrac. Why does Haskell insist on this, and how can I rewrite completeFacts so that x can just be an Integral?
Thanks!
It's because you didn't convert fact to a RealFrac before doing division:
in tryForFact (fact:fs) (floor (fromIntegral x / fromIntegral fact))
You've said that fact = findAFact x, which has type Integral x => x, but you're using it in a division with /, so it thinks it needs to satisfy both Integral and RealFrac.
What would actually be better is to just use div instead (I've also cleaned up the code a little bit so that it's easier to read and you aren't shadowing an existing binding for x):
completeFacts :: Integral x => x -> [x]
completeFacts x = tryForFact [] x
where
tryForFact fs 1 = fs
tryForFact fs y = let fact = findAFact y
in tryForFact (fact:fs) (y `div` fact)
The floor and / functions are what tripped you up.
(floor ((fromIntegral x) / fact))
Try using div instead.
fromIntegral x `div` fact

"No instance for .. ", Haskell'98 code on GHC7.8.3

I'm trying out the attached code for linear regression with automatic differentiation.
It specifies a datatype [Dual][2] made of two Floats, and declares it to be instance of Num, Fractional and Floating.
As in all fitting/regression tasks, there's a scalar cost function, parametrized by the fitting parameters c and m, and an optimizer which improves on estimates of these two parameters by gradient descent.
Question
I'm using GHC 7.8.3, and the authors explicitly mention that this is H98 code (I mentioned it in the title because it's the only substantial difference I can think of between my setup and the Author's, however plz correct if wrong).
Why does it choke within the definition of the cost function?
My understanding is: the functions idD and constD map Floats to Duals, g is polymorphic (it can perform algebraic operations on Dual inputs because Dual inherits from Num, Fractional and Floating), and deriv maps Duals to Doubles.
The type signature for g (the eta-reduced cost function wrt the data) was inferred. I tried omitting it, and making it more general by substituting a Floating type constraint to the Fractional one.
Moreover, I tried converting the numeric types of c and m inline with (fromIntegral c :: Double), to no avail.
Specifically this code gives this error:
No instance for (Integral Dual) arising from a use of ‘g’
In the first argument of ‘flip’, namely ‘g’
In the expression: flip g (constD c)
In the second argument of ‘($)’, namely ‘flip g (constD c) $ idD m’
Any hints, please? I'm sure it's a very noob question, but I just don't get it.
The complete code is the following:
{-# LANGUAGE NoMonomorphismRestriction #-}
module ADfw (Dual(..), f, idD, cost) where
data Dual = Dual Double Double deriving (Eq, Show)
constD :: Double -> Dual
constD x = Dual x 0
idD :: Double -> Dual
idD x = Dual x 1.0
instance Num Dual where
fromInteger n = constD $ fromInteger n
(Dual x x') + (Dual y y') = Dual (x+y) (x' + y')
(Dual x x') * (Dual y y') = Dual (x*y) (x*y' + y*x')
negate (Dual x x') = Dual (negate x) (negate x')
signum _ = undefined
abs _ = undefined
instance Fractional Dual where
fromRational p = constD $ fromRational p
recip (Dual x x') = Dual (1.0 / x) (- x' / (x*x))
instance Floating Dual where
pi = constD pi
exp (Dual x x') = Dual (exp x) (x' * exp x)
log (Dual x x') = Dual (log x) (x' / x)
sqrt (Dual x x') = Dual (sqrt x) (x' / (2 * sqrt x))
sin (Dual x x') = Dual (sin x) (x' * cos x)
cos (Dual x x') = Dual (cos x) (x' * (- sin x))
sinh (Dual x x') = Dual (sinh x) (x' * cosh x)
cosh (Dual x x') = Dual (cosh x) (x' * sinh x)
asin (Dual x x') = Dual (asin x) (x' / sqrt (1 - x*x))
acos (Dual x x') = Dual (acos x) (x' / (-sqrt (1 - x*x)))
atan (Dual x x') = Dual (atan x) (x' / (1 + x*x))
asinh (Dual x x') = Dual (asinh x) (x' / sqrt (1 + x*x))
acosh (Dual x x') = Dual (acosh x) (x' / (sqrt (x*x - 1)))
atanh (Dual x x') = Dual (atanh x) (x' / (1 - x*x))
-- example
-- f = sqrt . (* 3) . sin
-- f' x = 3 * cos x / (2 * sqrt (3 * sin x))
-- linear fit sum-of-squares cost
-- cost :: Fractional s => s -> s -> [s] -> [s] -> s
cost m c x y = (/ (2 * (fromIntegral $ length x))) $
sum $ zipWith errSq x y
where
errSq xi yi = zi * zi
where
zi = yi - (m * xi + c)
-- test data
x_ = [1..10]
y_ = [a | a <- [1..20], a `mod` 2 /= 0]
-- learning rate
gamma = 0.04
g :: (Integral s, Fractional s) => s -> s -> s
g m c = cost m c x_ y_
deriv (Dual _ x') = x'
z_ = (0.1, 0.1) : map h z_
h (c, m) = (c - gamma * cd, m - gamma * md) where
cd = deriv $ g (constD m) $ idD c
md = deriv $ flip g (constD c) $ idD m
-- check for convergence
main = do
take 2 $ drop 1000 $ map (\(c, m) -> cost m c x_ y_) z_
take 2 $ drop 1000 $ z_
where the test data x_ and y_ are arrays and the learning rate gamma a scalar.
[2]: The two fields of a Dual object are in fact adjoint one with the other, if we see the derivative as an operator
First, (Integral s, Fractional s) makes no sense; Integral is for Euclidean domains (ones with div and mod), while Fractional is for fields (ones with /). If you have true division all your remainders are going to be zero... .
I think the problem is y_'s attempt to filter to odd numbers. Haskell 98 defines a 'stepped' range form for numbers, so you could write y_ as [1,3..19]. That should allow y_ to be used at the type [Dual], which should allow g to use it without needing the Integral constraint.
Edit: Ørjan Johansen points out that you need an Enum instance for Dual as well, which is actually fairly easy to implement (this is pretty standard for numeric types; I basically copied GHC's instance for Double (which is identical to its instance for Float, for example)):
instance Enum Dual where
succ x = x + 1
pred x = x - 1
toEnum = fromIntegral
fromEnum (Dual x _) = fromEnum x
enumFrom = numericEnumFrom
enumFromTo = numericEnumFromTo
enumFromThen = numericEnumFromThen
enumFromThenTo = numericEnumFromThenTo
In the original code, I don't see a type signature for g. In your code, you have specifically written
g :: (Integral s, Fractional s) => s -> s -> s
The error message says there's no Integral instance for Dual. The code manually defines instances for Num and Fractional, but not Integral.
I'm not actually sure why g needs to be Integral. If you remove that constraint, the code may even work...
EDIT: It seems the Integral instance is necessary because of your use of mod to generate test data. I'm not really sure what this huge block of code does, but I suspect if you apply fromIntegral to convert everything to (say) Double, then it may work.
(I suspect making Dual an instance of Integral is probably not what the original authors intended. Then again, I don't really understand the code, so...)

Haskell: Understanding algebraic data types better

I'm trying to construct an algebraic data type that represents polynomials. Given the definition that an Integer constant is a polynomial and that if you add two polynomials or multiply two polynomials, it results in a polynomial.
I'm having a difficult time understanding how algebraic data types work in general and how I would even go about producing this. I currently have
data Poly = Const Int |
Add Poly Poly |
Mult Poly Poly
However I don't know what this even means or how to use it, I'm simply going off of examples I've seen of algebraic data types.
I've seen types like
data Tree = NullT |
Node Int Tree Tree
That makes more sense to me, and how to use it. The polynomial example seems so abstract I don't know where to start.
Edit: When I try to implement simple testing functions like:
evalPoly :: Poly -> Int
evalPoly (Const n) = n
I'm met with the error
*Polynomial> evalPoly Poly 1
<interactive>:25:10: Not in scope: data constructor ‘Poly’
*Polynomial>
Edit again: Thank you for all your suggestions and help, it's helped me produce something that's working for my purposes!
You seem to want to make an ADT for polynomials, but I'd prefer to use a Map. First some imports:
import qualified Data.Map as M
import Data.Function (on)
A polynomial is a Map from powers of x to coefficients.
newtype Poly a n = Poly {coeffMap :: M.Map n a} deriving (Show)
lift f = Poly . f . coeffMap
Let's make some simple polynomials:
zero = Poly M.empty -- none of the powers have non-zero coefficients
x = Poly $ M.singleton 1 1 -- x^1 has coefficient 1
constant 0 = zero
constant a = Poly $ M.singleton 0 a -- x^0 has coefficient a
A standard thing to do with a polynomial is evaluate it with a particular value for x.
The fold here takes the partially-calculated b and adds on the new term, a*x^n:
evalAt :: (Num a, Integral n) => a -> Poly a n -> a
evalAt x = M.foldrWithKey (\n a b -> b + a*x^n) 0 . coeffMap
If we want to use a Map function, we can lift it from Map n a to Poly n a.
I'd like to be able to map on the coefficients, but I don't want to make this an instance of Functor because it's a classic student error to apply operations like squaring, applying trigonometrical or logarithmic functions or taking square roots term by term, when in fact only a tiny few things like scalar multiplication, differentiation and integration work like this. Providing fmap encourages you to do wong things like fmap (+1) instead of (+ (constant 1)).
mapCoeffs :: (a -> b) -> Poly a n -> Poly b n
mapCoeffs f = lift (fmap f)
Maps already collect like terms automatically, but we'll want to omit terms with zero coefficients:
strikeZeros :: (Num a,Eq a) => Poly a n -> Poly a n
strikeZeros = lift $ M.filter (/= 0)
Now we can make the instances:
instance (Eq a,Num a,Ord n,Num n) => Eq (Poly a n) where
f == g = f - g == zero
instance (Eq a,Num a,Num n,Ord n) => Num (Poly a n) where
fromInteger = constant . fromInteger
signum (Poly m) | M.null m = zero
| otherwise = let (n,a) = M.findMax m in
Poly $ M.singleton n (signum a)
abs = mapCoeffs abs
negate = mapCoeffs negate
(+) = (strikeZeros.) . (Poly.) . ((M.unionWith (+)) `on` coeffMap)
(Poly m) * (Poly m') = Poly $
M.fromListWith (+) [(n+n',a*a') | (n,a)<-M.assocs m, (n',a')<-M.assocs m']
In action:
ghci> 3*x^4 + 6 + 2*x^7
Poly {coeffMap = fromList [(0,6),(4,3),(7,2)]}
Here's an alternative solution to the other one I posted.
You seem to want to make an ADT for polynomials, where I'd use a Map, but let's go with a list of terms. First some imports:
import Data.Function (on)
import Data.List (sortBy, groupBy, foldl1')
This way a polynomial is a list of terms, sorted with the highest power first, and a term is aX^n, represented by X a n
newtype Poly a n = Poly {terms :: [Term a n]} deriving (Show)
data Term a n = X {coeff :: a, power :: n} deriving (Eq,Show)
Let's make some simple polynomials:
zero = Poly []
x = Poly [X 1 1]
constant :: (Num a,Eq a,Num n) => a -> Poly a n
constant 0 = zero
constant a = Poly [X a 0]
Once we've defined the Num instance, we'll be able to make X 3 4 by writing 3*x^4.
A standard thing to do with a polynomial is evaluate it with a particular value for x.
subst :: (Num a, Integral n) => a -> Term a n -> a
subst x (X a n) = a * x ^ n
evalAt :: (Num a, Integral n) => a -> Poly a n -> a
evalAt x = sum . map (subst x) . terms
I'd like to be able to map on the coefficients, but I don't want to make this an instance of Functor because it's a classic student error to apply operations like squaring, applying trigonometrical or logarithmic functions or taking square roots term by term, when in fact only a tiny few things like scalar multiplication, differentiation and integration work like this. Providing fmap encourages you to do wong things like fmap (+1) instead of (+ (constant 1)).
mapCoeffs :: (a -> b) -> Poly a n -> Poly b n
mapCoeffs f = Poly . map f' . terms
where f' (X a n) = X (f a) n
We'll need to add and multiply terms, and collect like terms. When we collect like terms, we sort in reverse order of power and omit terms with zero coefficients.
addTerm (X a n) (X b m) | n == m = X (a+b) n
| otherwise = error "addTerm: mismatched powers"
multTerm (X a n) (X b m) = X (a*b) (n+m)
collectLikeTerms :: (Num a, Ord n, Eq a) => Poly a n -> Poly a n
collectLikeTerms = Poly . filter ((/= 0).coeff) -- no zero coeffs
. map (foldl1' addTerm) -- add the like powers
. groupBy ((==) `on` power) -- group the like powers
. sortBy (flip compare `on` power) -- sort in reverse powers
. terms
Now we can make the instances:
instance (Eq a,Num a,Ord n,Num n) => Eq (Poly a n) where
f == g = f - g == zero
instance (Eq a,Num a,Num n,Ord n) => Num (Poly a n) where
fromInteger = constant . fromInteger
signum (Poly []) = zero
signum (Poly (t:_)) = constant . signum . coeff $ t
abs = mapCoeffs abs
negate = mapCoeffs negate
(+) = (collectLikeTerms.) . (Poly.) . ((++) `on` terms)
(Poly ts) * (Poly ts') = collectLikeTerms $ Poly [multTerm t t' | t<-ts, t'<-ts']
In action:
ghci> 5*x^2 + 6*x^7 + 2
Poly {terms = [X {coeff = 6, power = 7},X {coeff = 5, power = 2},X {coeff = 2, power = 0}]}

Resources