Haskell Bounded DataTypes, constructed from value-bounds - haskell

I have the following type in Haskell, to represent values between 0&23. There's more for handling the arithmetic; elided here for space.
newtype N24 = N_24 Word16
deriving (Enum, Eq, Integral, NFData, Ord, Real, Show)
toN24 ∷ (Integral α, Num α) ⇒ α → N24
toN24 n#(toInteger → n') | n' < toInteger (minBound #N24) = throw Underflow
| n' > toInteger (maxBound #N24) = throw Overflow
| otherwise = N_24 (fromIntegral n)
instance Bounded N24 where
minBound = N_24 0
maxBound = N_24 23
Now, I want to build a similar type for N60. And another for N12.
My question is, can I design a higher-order type(?), e.g., 'BoundedN' such that I could declare
n60 :: BoundedN 60
n12 :: BoundedN 12
that implemented the above, but without having to copy-and-paste the entire definition. I've tried to use Reflection, but honestly, I'm not understanding it and just bouncing on the keys trying to find stuff that works isn't getting me anywhere. I could do it with TemplateHaskell, but I consider that a last resort (at best, it will be relatively hard to read, I fear).

It is possible to design such a type; indeed, it has already been done! The finite-typelits library defines a type Finite n, which can only be inhabited by the values from 0 to n-1. For instance, Finite 5 is inhabited by the numbers 0–4, but does not permit any other value. This functionality relies on the DataKinds extension, which allows the use of integers (amongst other things) at the type level. Take a look at the source code of the library if you’re interested in seeing how this works; the most important part is:
-- | Finite number type. #'Finite' n# is inhabited by exactly #n# values. Invariants:
--
-- prop> getFinite x < natVal x
-- prop> getFinite x >= 0
newtype Finite (n :: Nat) = Finite Integer
deriving (Eq, Ord, Generic)
-- | Convert an 'Integer' into a 'Finite', throwing an error if the input is out of bounds.
finite :: KnownNat n => Integer -> Finite n
finite x = result
where
result = if x < natVal result && x >= 0
then Finite x
else error $ "finite: Integer " ++ show x ++ " is not representable in Finite " ++ show (natVal result)
-- | Convert a 'Finite' into the corresponding 'Integer'.
getFinite :: Finite n -> Integer
getFinite (Finite x) = x

Related

Dependent types: Crossing the type/kind (runtime/compiletime) barrier

While venturing deeper into Haskell's dependent types I keep bumping into problems with the strict separation of run-time and compile-time checks.
Let me demonstrate the issue(s) with a little example of integers with a given bit-length.
{-# LANGUAGE DataKinds, GADTs, TypeFamilies, TypeOperators #-}
import GHC.TypeNats
import Data.Bits
data Sign = Signed | Unsigned
data Int_ (s::Sign) (n::Nat) where
Int_ :: Integer -> Int_ Signed n
UInt_ :: Integer -> Int_ Unsigned n
It's a type Int s n with signature s and bit-length n.
Some useful class instances would look like this:
instance (KnownNat n) => Show (Int_ s n) where
-- Verilog style
show i#(Int_ v) = (show.natVal) i <> "'sd" <> show v
show i#(UInt_ v) = (show.natVal) i <> "'ud" <> show v
instance (KnownNat n) => Eq (Int_ s n) where
(Int_ u) == (Int_ v) = u==v
(UInt_ u) == (UInt_ v) = u==v
Smart constructors that check bounds are
int8 :: Integer -> Int_ Signed 8
int8 i = if i<2^7 && i>=(-2^7) then Int_ i else error "int8 Overflow"
uint8 :: Integer -> Int_ Unsigned 8
uint8 i = if i>=0 && i<2^8 then UInt_ i else error "uint8 Overflow"
These smart constructors are already not so nice because the sanity check against overflow happens at run-time.
Problem 1: I have no clue how to write a smart constructor that would stop me from creating silly ints at compile-time. Moreover I'd need two types of constructors, one with the run-time check and one with the compile-time check.
This 'duplication' problem, that is needing one set of operations with run-time checks and another set of operations for compile-time checks is quite common.
For example, a concatenation operation would look like this:
(.++) :: (KnownNat m, KnownNat n) => Int_ Unsigned m
-> Int_ Unsigned n -> Int_ Unsigned (m+n)
i#(UInt_ x) .++ j#(UInt_ y) = UInt_ (x*2^(natVal j)+y)
and here's a shift operation:
(.>>) :: Int_ s m -> Int -> Int_ s m
i#(UInt_ x) .>> n = UInt_ (x `quot` (2 ^ n))
i#(Int_ x) .>> n = Int_ (x `quot` (2 ^ n))
It's a sensible definition, but it would also be sensible to let .>> return a truncated Int_ s k (for the left shift it would in fact be the more sensible thing to do). I.e.
(.>>) :: Int_ s m -> Nat n -> Int_ s (m-n) -- not proper syntax
It clearly isn't as simple as that: m-n can't be negative - coming back to the bounds check problem above.
Problem 2, a fundamental one, I believe, is that sometimes I know the n to shift by at compile-time, and sometimes I don't. When I do know the n at compile-time I'd like to have the compile-time checks. When n is dynamic (determined at run-time) I obviously can't have them. Is there a way to set this up in order to mix-and-match, so to speak, i.e. avoid the duplication of all the logic, one at the value-level and one at the type level, plus the glue between the two?
My hunch is that I need some type class that introduces polymorphism over Int and some Nat sort of thing, but I'm totally unsure where this is going.

Haskell - create instance of class (how to do it right?)

I read the chapter about that topic in "learn you a haskell" and tried to find some hints on different websites - but are still unable to solve the following task.
Im a haskell newbie (6 weeks of "experience") and its the first time I have to work with instances.
So here is the task, my code has to pass the HUnit tests and the end. I tried to implement the instances but it seems like I´ve missed something there. Hope you can help me! THX
module SemiGroup where
{-
A type class 'SemiGroup' is given. It has exactly one method: a binary operation
called '(<>)'. Also a data type 'Tree' a newtype 'Sum' and a newtype 'Max' are
given. Make them instances of the 'SemiGroup' class.
The 'Tree' instance should build a 'Branch' of the given left and right side.
The 'Sum' instance should take the sum of its given left and right side. You need
a 'Num' constraint for that.
The 'Max' instance should take the maximum of its given left and right side. You
also need a constraint for that but you have to figure out yourself which one.
This module is not going to compile until you add the missing instances.
-}
import Test.HUnit (runTestTT,Test(TestLabel,TestList),(~?=))
-- | A semigroup has a binary operation.
class SemiGroup a where
(<>) :: a -> a -> a
-- Leaf = Blatt, Branch = Ast
-- | A binary tree data type.
data Tree a = Leaf a
| Branch (Tree a) (Tree a)
deriving (Eq,Show)
-- | A newtype for taking the sum.
newtype Sum a = Sum {unSum :: a}
-- | A newtype for taking the maximum.
newtype Max a = Max {unMax :: a}
instance SemiGroup Tree where
(<>) x y = ((x) (y))
instance SemiGroup (Num Sum) where
(<>) x y = x+y
instance SemiGroup (Eq Max) where
(<>) x y = if x>y then x else y
-- | Tests the implementation of the 'SemiGroup' instances.
main :: IO ()
main = do
testresults <- runTestTT tests
print testresults
-- | List of tests for the 'SemiGroup' instances.
tests :: Test
tests = TestLabel "SemiGroupTests" (TestList [
Leaf "Hello" <> Leaf "Friend" ~?= Branch (Leaf "Hello") (Leaf "Friend"),
unSum (Sum 4 <> Sum 8) ~?= 12,
unMax (Max 8 <> Max 4) ~?= 8])
I tried something like:
class SemiGroup a where
(<>) :: a -> a -> a
-- Leaf = Blatt, Branch = Ast
-- | A binary tree data type.
data Tree a = Leaf a
| Branch (Tree a) (Tree a)
deriving (Eq,Show)
-- | A newtype for taking the sum.
newtype Sum a = Sum {unSum :: a}
-- | A newtype for taking the maximum.
newtype Max a = Max {unMax :: a}
instance SemiGroup Tree where
x <> y = Branch x y
instance Num a => SemiGroup (Sum a) where
x <> y = x+y
instance Eq a => SemiGroup (Max a) where
x <> y = if x>y then x else y
But there a still some failures left! At least the wrap/unwrap thing that "chi" mentioned. But I have no idea. maybe another hint ? :/
I fail to see how to turn Tree a into a semigroup (unless it has to be considered up-to something).
For the Sum a newtype, you need to require that a is of class Num. Then, you need to wrap/unwrap the Sum constructor around values so that: 1) you take two Sum a, 2) you convert them into two a, which is a proper type over which + is defined, 3) you sum them, 4) you turn the result back into a Sum a.
You can try to code the above yourself starting from
instance Num a => Semigroup (Sum a) where
x <> y = ... -- Here both x and y have type (Sum a)
The Max a instance will require a similar wrap/unwrap code.
A further hint: to unwrap a Sum a into an a you can use the function
unSum :: Sum a -> a
to wrap an a into a Sum a you can use instead
Sum :: a -> Sum a
Note that both functions Sum, unSum are already implicitly defined by your newtype declaration, so you do not have to define them (you already did).
Alternatively, you can use pattern matching to unwrap your values. Instead of defining
x <> y = ... -- x,y have type Sum a (they are wrapped)
you can write
Sum x <> Sum y = ... -- x,y have type a (they are unwrapped)
Pay attention to the types. Either manually, or with some help from GHCi, figure out the type of the functions you are writing -- you'll find they don't match the types that the typeclass instance needs. You'll use wrapping and unwrapping to adjust the types until they work.

Deriving Data.Complex in Haskell

I have code that looks a little like the following:
import Data.Complex
data Foo = N Number
| C ComplexNum
data Number = Int Integer
| Real Float
| Rational Rational
deriving Show
data ComplexNum = con1 (Complex Integer)
| con2 (Complex Float)
| con3 (Complex Rational)
deriving Show
But this seems like a bad way to do it. I would rather have
data Foo = N Number
| C (Complex Number)
and construct a ComplexNumber with something similar to ComplexNumber $ Real 0.0.
The question is how to make Complex Number possible. Since all of the types in Number have corresponding Complex instances, can I just add deriving Complex to Number?
The Haskell approach is to have different types for Complex Float and Complex Int rather than trying to unify them into one type. With type classes you can define all of these types at once:
data Complex a = C a a
instance Num a => Num (Complex a) where
(C x y) + (C u v) = C (x+u) (y+v)
(C x y) * (C u v) = C (x*u-y*v) (x*v+y*u)
fromInteger n = C (fromInteger n) 0
...
This at once defines Complex Int, Complex Double, Complex Rational, etc. Indeed it even defines Complex (Complex Int).
Note that this does not define how to add a Complex Int to a Complex Double. Addition (+) still has the type (+) :: a -> a -> a so you can only add a Complex Int to a Complex Int and a Complex Double to another Complex Double.
In order to add numbers of different types you have to explicitly convert them, e.g.:
addIntToComplex :: Int -> Complex Double -> Complex Double
addIntToComplex n z = z + fromIntegral n
Have a look at http://www.haskell.org/tutorial/numbers.html section 10.3 for more useful conversion functions between Haskell's numeric type classes.
Update:
In response to your comments, I would suggest focusing more on the operations and less on the types.
For example, consider this definition:
onethird = 1 / 3
This represents the generic "1/3" value in all number classes:
import Data.Ratio
main = do
putStrLn $ "as a Double: " ++ show (onethird :: Double)
putStrLn $ "as a Complex Double: " ++ show (onethird :: Complex Double)
putStrLn $ "as a Ratio Int: " ++ show (onethird :: Ratio Int)
putStrLn $ "as a Complex (Ratio Int): " ++ show (onethird :: Complex (Ratio Int))
...
In a sense Haskell let's the "user" decide what numeric type the expression should be evaluated as.
This doesn't appear to be legal Haskell code. You have three constructors of type ComplexNum all named Complex. Also, data types must begin with a capital letter, so foo isn't a valid type. It's hard to tell what you mean, but I'll take a stab:
If you have a type
data Complex a = (a,a)
you can keep your definition of Number and define foo as:
data Foo = N Number
| C (Complex Number)

Pattern matching on length using this GADT:

I've defined the following GADT:
data Vector v where
Zero :: Num a => Vector a
Scalar :: Num a => a -> Vector a
Vector :: Num a => [a] -> Vector [a]
TVector :: Num a => [a] -> Vector [a]
If it's not obvious, I'm trying to implement a simple vector space. All vector spaces need vector addition, so I want to implement this by making Vector and instance of Num. In a vector space, it doesn't make sense to add vectors of different lengths, and this is something I would like to enforce. One way I thought to do it would be using guards:
instance Num (Vector v) where
(Vector a) + (Vector b) | length a == length b =
Vector $ zipWith (+) a b
| otherwise =
error "Only add vectors with the same length."
There is nothing really wrong with this approach, but I feel like there has to be a way to do this with pattern matching. Perhaps one way to do it would be to define a new data type VectorLength, which would look something like this:
data Length l where
AnyLength :: Nat a => Length a
FixedLength :: Nat a -> Length a
Then, a length component could be added to the Vector data type, something like this:
data Vector (Length l) v where
Zero :: Num a => Vector AnyLength a
-- ...
Vector :: Num a => [a] -> Vector (length [a]) [a]
I know this isn't correct syntax, but this is the general idea I'm playing with. Finally, you could define addition to be
instance Num (Vector v) where
(Vector l a) + (Vector l b) = Vector $ zipWith (+) a b
Is such a thing possible, or is there any other way to use pattern matching for this purpose?
What you're looking for is something (in this instance confusingly) named a Vector as well. Generally, these are used in dependently typed languages where you'd write something like
data Vec (n :: Natural) a where
Nil :: Vec 0 a
Cons :: a -> Vec n a -> Vec (n + 1) a
But that's far from valid Haskell (or really any language). Some very recent extensions to GHC are beginning to enable this kind of expression but they're not there yet.
You might be interested in fixed-vector which does a best approximation of a fixed Vector available in relatively stable GHC. It uses a number of tricks between type families and continuations to create classes of fixed-size vectors.
Just to add to the example in the other answer - this nearly works already in GHC 7.6:
{-# LANGUAGE DataKinds, GADTs, KindSignatures, TypeOperators #-}
import GHC.TypeLits
data Vector (n :: Nat) a where
Nil :: Vector 0 a
Cons :: a -> Vector n a -> Vector (n + 1) a
That code compiles fine, it just doesn't work quite the way you'd hope. Let's check it out in ghci:
*Main> :t Nil
Nil :: Vector 0 a
Good so far...
*Main> :t Cons "foo" Nil
Cons "foo" Nil :: Vector (0 + 1) [Char]
Well, that's a little odd... Why does it say (0 + 1) instead of 1?
*Main> :t Cons "foo" Nil :: Vector 1 String
<interactive>:1:1:
Couldn't match type `0 + 1' with `1'
Expected type: Vector 1 String
Actual type: Vector (0 + 1) String
In the return type of a call of `Cons'
In the expression: Cons "foo" Nil :: Vector 1 String
Uh. Oops. That'd be why it says (0 + 1) instead of 1. It doesn't know that those are the same. This will be fixed (at least this case will) in GHC 7.8, which is due out... In a couple months, I think?

How do you use the Bounded typeclass in Haskell to define a type with a floating point range?

I expected the following code to fail with a type error due to violation of the minBound and maxBound. But, as you can see, it goes through without flagging an error.
{-# OPTIONS_GHC -XTypeSynonymInstances #-}
module Main where
type Probability = Float
instance Bounded Probability where
minBound = 0.0
maxBound = 1.0
testout :: Float -> Probability
testout xx = xx + 1.0
main = do
putStrLn $ show $ testout 0.5
putStrLn $ show $ testout (-1.5)
putStrLn $ show $ testout 1.5
In the Prelude I get this
*Main> :type (testout 0.5)
(testout 0.5) :: Probability
And at the prompt I get this:
[~/test]$runhaskell demo.hs
1.5
-0.5
2.5
Clearly I'm not declaring Bounded properly, and I'm sure I'm doing something wrong syntactically. There isn't much simple stuff on Google regarding Bounded typeclasses, so any help would be much appreciated.
That's not what Bounded is for. Bounded a just defines the functions minBound :: a and maxBound :: a. It does not induce any special checking or anything.
You can define a bounded type using a so-called smart constructor. That is:
module Probability (Probability) where
newtype Probability = P { getP :: Float }
deriving (Eq,Ord,Show)
mkP :: Float -> Probability
mkP x | 0 <= x && x <= 1 = P x
| otherwise = error $ show x ++ " is not in [0,1]"
-- after this point, the Probability data constructor is not to be used
instance Num Probability where
P x + P y = mkP (x + y)
P x * P y = mkP (x * y)
fromIntegral = mkP . fromIntegral
...
So the only way to make a Probability is to use the mkP function eventually (this is done for you when you use numeric operations given our Num instance), which checks that the argument is in range. Because of the module's export list, outside of this module is it not possible to construct an invalid probability.
Probably not the two-liner you were looking for, but oh well.
For extra composability, you could factor out this functionality by making a BoundCheck module instead of Probability. Just like above, except:
newtype BoundCheck a = BC { getBC :: a }
deriving (Bounded,Eq,Ord,Show)
mkBC :: (Bounded a) => a -> BoundCheck a
mkBC x | minBound <= x && x <= maxBound = BC x
| otherwise = error "..."
instance (Bounded a) => Num (BoundCheck a) where
BC x + BC y = mkBC (x + y)
...
Thus you can get the functionality you were wishing was built in for you when you asked the question.
To do this deriving stuff you may need the language extension {-# LANGUAGE GeneralizedNewtypeDeriving #-}.

Resources