Enum instance for tuples in Haskell - haskell
I'd like to define a tuple (x, y) as an instance of Enum class, knowing that both x and y are instances of Enum. A following try:
instance (Enum x, Enum y) => Enum (x, y) where
toEnum = y
enumFrom x = (x, x)
only results in error (y not in scope). I'm new to Haskell, could somebody explain how to declare such an instance?
instance (Enum x, Enum y) => Enum (x, y) where
In the above line, x and y are both types (type variables).
toEnum = y
enumFrom x = (x, x)
In the above two lines, x and y are both values ((value) variables). y-as-a-value has not been defined anywhere, that's what it not being in scope means.
As to how to declare such an instance, I'm not sure how you'd want fromEnum and toEnum to behave, for example.
Not a good idea if you ask me, but anyway —
To make an instance of a type class, you need to look at the signatures.
class Enum a where
succ :: a -> a
pred :: a -> a
toEnum :: Int -> a
fromEnum :: a -> Int
enumFrom :: a -> [a]
enumFromThen :: a -> a -> [a]
enumFromTo :: a -> a -> [a]
enumFromThenTo :: a -> a -> a -> [a]
So in your case
toEnum :: Int -> (x, y)
but toEnum = y isn't even defined, because y is just a type, not a value or constructor. Possibilities would be
toEnum n = (toEnum 0, toEnum n)
or
toEnum n = (toEnum n, toEnum n)
or
toEnum n = (toEnum $ n`div`2, toEnum $ (n+1)`div`2)
As for enumFrom, your version has signature
enumFrom :: a -> (a,a)
but we need
enumFrom :: (x,y) -> [(x,y)]
what definition is suitable depends on how toEnum was defined; for my first suggestion it would be
enumFrom (x,y) = [ (x,y') | y' <- enumFrom y ]
Reading Dietrich Epp's comment
It's not actually possible to create a useful Enum (x, y) from Enum x and Enum y. You'd need additional context, like Bounded x, Bounded y, Enum x, Enum y => Enum (x, y).
I thought about ways it could actually be done meaningfully. It seems possible sure enough, a bijection ℤ → ℤ2 exists. My suggestion:
[ ...
, (-3,-3), (-3,-2), (-2,-3), (-3,-1), (-1,-3), (-3,0), (0,-3), (-3,1), (1,-3), (-3,2), (2,-3), (-3,3), (3,-3)
, (-2,3), (3,-2), (-1,3), (3,-1)
, (-2,-2), (-2,-1), (-1,-2), (-2,0), (0,-2), (-2,1), (1,-2), (-2,2), (2,-2)
, (-1,2), (2,-1)
, (-1,-1), (-1,0), (0,-1), (-1,1), (1,-1)
, (0,0)
, (1,0), (0,1), (1,1)
, (2,0), (0,2), (2,1), (1,2), (2,2)
, (3,0), (0,3), (3,1), (1,3), (3,2), (2,3), (3,3)
, ... ]
Note that this reduces to a bijection ℕ → ℕ2 as well, which is important because some Enum instances don't go into the negative range and others do.
Implementation:
Let's make a plain (Int,Int) instance; it's easy to generalize that to your desired one. Also, I'll only treat the positive cases.
Observe that there are k^2 tuples between (0,0) and (excluding) (k,0). All other tuples (x,y) with max x y == k come directly after it. With that, we can define fromEnum:
fromEnum (x,y) = k^2 + 2*j + if permuted then 1 else 0
where k = max x y
j = min x y
permuted = y>x
for toEnum, we need to find an inverse of this function, i.e. knowing fromEnum -> n we want to know the parametes. k is readily calculated as floor . sqrt $ fromIntegral n. j is obtained similarly, simply with div 2 of the remainder.
toEnum n = let k = floor . sqrt $ fromIntegral n
(j, permdAdd) = (n-k^2) `divMod` 2
permute (x,y) | permdAdd>0 = (y,x)
| otherwise = (x,y)
in permute (k,j)
With fromEnum and toEnum, all the other functions are rather trivial.
Related
Where is .. defined?
I'm just wondering whether .. is actually defined in Haskell code anywhere, like in the Prelude? Is enumFromTo the same thing? I don't get which is the definition? enumFromTo x y = map toEnum [fromEnum x .. fromEnum y] [ e1 .. e3 ] = enumFromTo e1 e3
It's a part of the syntax, specified in the Report, section 3.10. Yes it gets translated into code using enumFrom etc. functions: To your edit of the question: the definitions you show are "default definitions" in the Enum typeclass. It says so right there in the Prelude you linked: class Enum a where succ, pred :: a -> a toEnum :: Int -> a fromEnum :: a -> Int enumFrom :: a -> [a] -- [n..] enumFromThen :: a -> a -> [a] -- [n,n'..] enumFromTo :: a -> a -> [a] -- [n..m] enumFromThenTo :: a -> a -> a -> [a] -- [n,n'..m] -- Minimal complete definition: -- toEnum, fromEnum -- _______ -- ____ -- NOTE: these default methods only make sense for types -- **** NB -- that map injectively into Int using fromEnum -- and toEnum. succ = toEnum . (+1) . fromEnum pred = toEnum . (subtract 1) . fromEnum enumFrom x = map toEnum [fromEnum x ..] enumFromTo x y = map toEnum [fromEnum x .. fromEnum y] enumFromThen x y = map toEnum [fromEnum x, fromEnum y ..] enumFromThenTo x y z = map toEnum [fromEnum x, fromEnum y .. fromEnum z] So each type a that is in Enum must provide the definitions for at least toEnum :: Int -> a and fromEnum :: a -> Int. If it doesn't provide its own definition for e.g. enumFromTo :: a -> a -> [a] then its default definition will be used: enumFromTo :: a -> a -> [a] enumFromTo x y = map toEnum [fromEnum x .. fromEnum y ] -- └a┘└a┘ └a┘ └a┘ -- └──Int────┘ └──Int────┘ -- └Int->a┘ └─────────[Int]───────────┘ -- └───────────────[a]────────────────────┘ And for the Int type itself there is a specific definition defined somewhere in the library, so the default definition of enumFromTo is not used for Int, thus there is no vicious circle.
Foldl with lambda expresion
Hi I'm trying to sum a list of tuples into a tuple with the foldl function, I tryed it with using as parameter a lambda expresion but it's giving out a wrong value here the code: data Point = Point {x,y :: Float} sumPoint :: [Point] -> (Float,Float) sumPoint xs = foldl (\(a,b) x-> (0+a,0+b)) (0.0,0.0) xs It should come out sumPoint [Point 2 4, Point 1 2, Point (-1) (-2)] = (2.0,4.0) But im getting (0.0,0.0) How is this making any sense?
To be a little structural you better define operations among Point type values and then convert the Point type to Tuple wherever needed. Otherwise you may directly use Tuple and discard the Point type. data Point = Point {x,y :: Float} deriving Show toTuple :: Point -> (Float, Float) toTuple p = (x p, y p) addPts :: Point -> Point -> Point addPts p q = Point (x p + x q) (y p + y q) sumPts :: [Point] -> Point sumPts = foldl addPts (Point 0 0) So what you need is toTuple . sumPts function. *Main> :t toTuple . sumPts toTuple . sumPts :: [Point] -> (Float, Float)
I changed it to sumPoint xs = foldl (\(a,b) (Point x y)-> (x+a,y+b)) (0.0,0.0) xs The problem was I was ignoring the x and at 0+a is nothing happening.
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!
Haskell class instance
It's my first exercise to understand the classes in Haskell. My problem is how to define the functions that I have declared in the class and how to test them by terminal ghci. I explain step by step what I did: type Point2d = (Int, Int) -- point type Vector2d = (Int, Int) -- vector data Shape = Line Point2d Point2d | Triangle Point2d Point2d Point2d deriving (Eq, Show) class ClassShape s where name :: s -> String perim :: s -> Int -- given a CShape calculates the perimeter move :: s -> Vector2d -> s Now, I declare s as ClassShape instance, by implementing the corresponding functions. nameShape :: Shape s -> String nameShape Line = "Line" nameShape Triangle = "Triangle" perimShape :: Shape s -> Int perimShape Line a b = 999 -- ... perimShape Triangle a b c = 999 -- ... Here's my problem: how should I declare the functions? I just need to see an "example" to understand the concept. The error that Haskell returns is: `Shape' is applied to too many type arguments In the type signature for `nameShape': nameShape :: Shape s -> String `Shape' is applied to too many type arguments In the type signature for `perimShape': perimShape :: Shape s -> Int Then, how do I test the program on Haskell? Thanks to all.
Note that nameShape function will not work, because there is no Shape s type defined. Remember that s is a type variable. Only if you have defined Shape s type constructor you can use them. You have defined Shape type in your definition but not Shape s. For defining instance of typeclass, you have to do something like this: instance ClassShape Shape where name (Line _ _) = "Line" name (Triangle _ _ _) = "Triangle" perim (Line x y) = undefined -- Calculate perimiter using x and y perim (Triangle x y z) = undefined move (Line x y) = undefined move (Triangle x y z) = undefined You have to fill the undefined with working parts.
You're making a common confusion of early Haskell programmers: using two different things which work in related ways (sum types and classes) to do the same thing in two different ways. Thus there are two problems: the "little" problem (what does this error mean?) and the "big" problem (why is your code shaped like this?). The Little Problem You wrote Shape s when you meant to just write Shape. The way you have defined Shape, it has kind * (that is, it is a concrete type) rather than kind * -> *, which is the kind of adjectives -- things like "a list of" or "a pair of" which are abstract until you give them a concrete type to modify ("a list of strings" is concrete, "a list of" is abstract). When you write Shape s you are applying Shape as an adjective to a type variable s but it's not an adjective; it's a noun. That is why you get the error: `Shape' is applied to too many type arguments Side note: you may be used to languages where the error message usually is not very well-related to the actual problem. In Haskell usually the compiler tells you exactly what is wrong, as it did in this case. The Big Problem Type classes are collections of unrelated types which can do the same things. The type class syntax passes an implicit context as a "constraint", this context can be implicit because it belongs to the type. You may need to read that last paragraph a few times in a quiet corner. Basically I mean to say that you can do the same thing as a type class with a data constructor for the context: data EqOrd s = EqOrdLib {getEq :: s -> s -> Bool, getCmp :: s -> s -> Ordering} -- this is just provided to us as a primitive by Haskell intEOL :: EqOrd Int intEOL = EqOrdLib (==) compare -- but we can then define things like this: listEOL :: EqOrd x -> EqOrd [x] listEOL (EqOrdLib base_eq base_cmp) = EqOrdLib list_eq list_cmp where list_cmp [] [] = EQ list_cmp (_:_) [] = GT list_cmp [] (_:_) = LT list_cmp (x:xs) (y:ys) = case base_cmp x y of LT -> LT GT -> GT EQ -> list_cmp xs ys list_eq xs ys = list_cmp xs ys == EQ Now to use that sort of context, you would have to write explicitly: quicksort :: EqOrd x -> [x] -> [x] quicksort _ [] = [] quicksort lib (p:els) = quicksort lib lesser ++ [p] ++ quicksort lib greater where cmp = getCmp lib p_less_than x = cmp x p == LT p_gte x = not . p_less_than greater = filter p_less_than els lesser = filter p_gte els See, we explicitly pass in this library of functions lib and explicitly pull out the comparison function cmp = getCmp lib. Type classes allow us to implicitly pass the library of functions, by stating up-front that the type itself only has one such library. We pass the library as a "constraint", so instead of EqOrd x -> [x] -> [x] you write Ord x => [x] -> [x] with the "fat arrow" of constraints. But secretly it means "when you ask me to use the < function on two values of type x, I know implicitly what library to get that function from and will get that function for you." Now: you have one type, Shape, so you don't need typeclasses. (Go back to the first paragraph above: Type classes are collections of unrelated types which can do the same things. If you want to do type classes then instead of the sum-type for Shape, let's define n-dimensional vectors of different types: class Vector v where (*.) :: (Num r) => r -> v r -> v r (.+.) :: (Num r) => v r -> v r -> v r norm :: (Num r, Floating r) => v r -> r -- another advantage of type classes is *default declarations* like: (.-.) :: (Num r) => v r -> v r -> v r v1 .-. v2 = v1 .+. (-1 *. v2) data V2D r = V2D r r deriving (Eq, Show) instance Vector V2D where s *. V2D x y = V2D (s * x) (s * y) V2D x1 y1 .+. V2D x2 y2 = V2D (x1 + x2) (y1 + y2) norm (V2D x y) = sqrt (x^2 + y^2) data V3D r = V3D r r r deriving (Eq, Show) instance Vector V3D where s *. V3D x y z = V3D (s * x) (s * y) (s * z) V3D x1 y1 z1 .+. V3D x2 y2 z2 = V3D (x1 + x2) (y1 + y2) (z1 + z2) norm (V3D x y z) = sqrt (x^2 + y^2 + z^2) Then we can write things like: newtype GeneralPolygon v r = Poly [v r] perimeter :: (Num r, Floating r, Vector v) -> GeneralPolygon v r -> r perimeter (Poly []) = 0 perimeter (Poly (x : xs)) = foldr (+) 0 (map norm (zipWith (.-.) (x : xs) (xs ++ [x]))) translate :: (Vector v, Num r) => GeneralPolygon v r -> v r -> GeneralPolygon v r translate (Poly xs) v = Poly (map (v .+.) xs) Making Typeclasses Work For You Now if you really want to, you can also unwrap your sum-type data declaration into a bunch of data declarations: data Line = Line Point2d Point2d deriving (Eq, Show) data Square = Square Point2d Point2d deriving (Eq, Show) data Triangle = Triangle Point2d Point2d Point2d deriving (Eq, Show) Now you can do something simple like: class Shape s where perim :: s -> Int move :: s -> Vector2d -> s Although I should say, you'll run into a problem when you want to do square roots for perimeters (sqrt is in the Floating typeclass, which Int does not have functions for, you'll want to change Int to Double or something).
Haskell applicative functor - compilation failure
I'm trying to chain together functions via the applicative functor pattern, but I'm having a problem compiling my code: import Control.Applicative buildMyList :: Float -> Float -> [Float] buildMyList ul tick = [p | p <- [0,tick..ul]] myFunctionChain :: [Float] myFunctionChain = reverse <$> buildMyList 100 1 When I attempt to compile this I get the following compilation error: Couldn't match type 'Float' with '[a0]' Expected type: [[a0]] Actual type: [Float] In the return type of call of 'buildMyList' It seems to me that I haven't managed to match the expected return context with the actual context. Not having enough experience in this area, I cant get any further!
The Applicative could be better explained using bulldMyList. Assume you want to build an array of square matrix: [(0,0), (0,1), (0,2), (1, 0) ...]. Using list comprehensions: buildMyMatrix :: Int -> Int -> [(Int, Int)] buildMyMatrix maxX maxY = [(x, y) | x <- [0..maxX], y <- [0..maxY]] Using applicative combinators it can be rewritten as: buildMyMatrix maxX maxY = pure (\x y -> (x, y)) <*> [0..maxX] <*> [0..maxY] And according to applicative laws we can rewrite pure f <*> x = f <$> x, for all f and x: buildMyMatrix maxX maxY = (\x y -> (x, y)) <$> [0..maxX] <*> [0..maxY] I had to use slightly more complicated buildMyMatrix, as your buildMyList is too trivial to benefit from Applicative: buildMyList :: Float -> Float -> [Float] buildMyList ul tick = [p | p <- [0,tick..ul]] buildMyList ul tick = id <$> [0,tick..ul] -- [by functor identity law]: buildMyList ul tick = [0,tick..ul]