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

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 #-}.

Related

Haskell Bounded DataTypes, constructed from value-bounds

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

Unexpected caching behavior using polymorphic records in Haskell

I've run into some unexpected behavior using polymorphic records in Haskell, where some values are not cached when I expect them to be cached.
Here is a minimal example:
{-# LANGUAGE RankNTypes #-}
import Debug.Trace
-- Prints out two "hello"s
data Translation = Trans { m :: forall a . Floating a => a }
g :: Floating a => a -> a
g x = x + 1
f :: Floating a => a -> a
f x = trace "hello" $ x - 2.0
-- Only one "hello"
-- data Translation = Trans { m :: Float }
--
-- f :: Float -> Float
-- f x = trace "hello" $ x - 2.0
main :: IO ()
main = do
let trans = Trans { m = f 1.5 }
putStrLn $ show $ m trans
putStrLn $ show $ m trans
In the example, I thought if the value f 1.5 was computed and stored in the field m, on the next time it is accessed, it would not be computed again. However, it seems to be recomputed on every access to the record field, as shown by the fact that "hello" is printed twice.
On the other hand, if we remove the polymorphism from the field, the value is cached as expected, and "hello" is only printed once.
I suspect this is due to the interaction of typeclasses (being treated as records) preventing memoization. However, I don't fully understand why.
I realized that compiling with -O2 makes the problem go away, however, this behavior occurs in a much larger system where compiling with -O2 does not seem to have any effect, therefore I'd like to understand the root cause of the problem, so I can fix the performance issues in the larger system.
Hold my beer.
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ConstraintKinds #-}
import Debug.Trace
data Dict c where Dict :: c => Dict c
-- An isomorphism between explicit dictionary-passing style (Dict c -> a)
-- and typeclass constraints (c => a) exists:
from :: (c => a) -> (Dict c -> a)
from v Dict = v
to :: (Dict c -> a) -> (c => a)
to f = f Dict
data Translation = Trans { m :: forall a . Floating a => a }
f1, f2 :: Dict (Floating a) -> a -> a
f1 = trace "hello" $ \Dict x -> x - 2.0
f2 = \Dict -> trace "hello" $ \x -> x - 2.0
main = do
let trans1 = Trans { m = to (flip f1 1.5) }
trans2 = Trans { m = to (flip f2 1.5) }
putStrLn "trans1"
print (m trans1)
print (m trans1)
putStrLn "trans2"
print (m trans2)
print (m trans2)
Take a second to predict what this will output before you run it. Then go ask your GHC if she agrees with your guess.
Clear as mud?
The basic distinction you need to draw here is right here in this significantly simplified example:
> g = trace "a" $ \() -> trace "b" ()
> g ()
a
b
()
> g ()
b
()
There is a separate notion of caching a function and caching its output. The latter is, simply, never done in GHC (though see discussion of what's going on with your optimized version below). The former may sound dumb, but it in fact is not so dumb as you might think; you could imagine writing a function which is, say, id if the collatz conjecture is true and not otherwise. In such a situation, it makes complete sense to only test the collatz conjecture once, and then cache whether we should behave as id or not forever afterwards.
Once you understand this basic fact, the next leap you must believe is that in GHC, typeclass constraints are compiled to functions. (The arguments to the function are typeclass dictionaries telling how each of the typeclass' methods behave.) GHC itself manages constructing and passing these dictionaries around for you, and in most cases it's quite transparent to the user.
But the upshot of this compilation strategy is this: a polymorphic but typeclass-constrained type is a function even if it doesn't appear to have function arrows in it. That is,
f 1.5 :: Floating a => a
looks like a plain old value; but in fact it is a function which takes a Floating a dictionary and produces a value of type a. So any computations that go into computing the value a are redone afresh each time this function is applied (read: used at a specific monomorphic type) because, after all, the precise value chosen depends critically on how the typeclass' methods behave.
This leaves only the question of why optimizations changed things in your situation. There I believe what happened is called "specialization", in which the compiler will try to notice when polymorphic things get used at a statically-known monomorphic type and make a binding for that. It goes something like this:
-- starting point
main = do
let trans = \dict -> trace "hello" $ minus dict (fromRational dict (3%2)) (fromRational dict (2%1))
print (trans dictForDouble)
print (trans dictForDouble)
-- specialization
main = do
let trans = \dict -> trace "hello" $ minus dict (fromRational dict (3%2)) (fromRational dict (2%1))
let transForDouble = trans dictForDouble
print transForDouble
print transForDouble
-- inlining
main = do
let transForDouble = trace "hello" $ minus dictForDouble (fromRational dict (3%2)) (fromRational dictForDouble (2%1))
print transForDouble
print transForDouble
In this last one the function-ness is gone; it is "as if" GHC has cached the output of trans when applied to the dictionary dictForDouble. (If you compile with optimizations and -ddump-simpl you will see it goes even further, doing constant-propagation to turn the minus ... stuff into just D# -0.5##. Whew!)
{-# LANGUAGE RankNTypes #-}
import Debug.Trace
--Does not get cached
data Translation = Trans { m :: forall a. Floating a => a }
f :: Floating a => a -> a
f x = trace "f" $ x - 2.0
Since a is a rigid type variable bound by a type expected by the context
forall a. Floating a => a you would have to cache the context as well
--Does get cached
data Translation' = Trans' { m' :: Float }
f' :: Float -> Float
f' x = trace "f'" $ x - 2.0
Since this is a value of type Float it can be computed once and cached afterwards.
main :: IO ()
main = do
let
trans = Trans { m = f 1.5 }
trans' = Trans' { m' = f' 1.5}
putStrLn $ show $ (m trans :: Double)
putStrLn $ show $ (m trans :: Float)
-- ^ you can evaluate it with 2 different contexts
putStrLn $ show $ (m' trans' :: Float)
putStrLn $ show $ (m' trans' :: Float)
-- ^ context fixed
Note that the former one does not get cached whether compiler optimization is turned on or off.
When they are both Float and you turn on optimization the problem is gone.
If you compile the larger system with optimization and it is to inefficient on some metric I would suspect that the problem lies somewhere else.

Haskell: Non type-variable argument in the constraint

I created some functions to get some comfort with 2D geometry.
In this example I use Geom2D from CubicBezier package.
Complete code of my program: https://gist.github.com/nskeip/3784d651ac646a67c5f246f048949af4
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-}
import Geom2D
left :: (Num a) => Point a -> a -> Point a
left (Point x y) n = Point (x - n) y
right :: (Num a) => Point a -> a -> Point a
right (Point x y) n = Point (x + n) y
up :: (Num a) => Point a -> a -> Point a
up (Point x y) n = Point x (y - n)
down :: (Num a) => Point a -> a -> Point a
down (Point x y) n = Point x (y + n)
They work like this:
> (Point 0 0) `up` 10
Point 0.0 -10.0
Where Point is defined like this:
data Point a = Point {
pointX :: !a,
pointY :: !a
} deriving (Eq, Ord, Functor, Foldable, Traversable)
And everything was fine untill I thought: "Hey, it would be nice to make that functions (actualy, operators) work with thigs like Line - not only Point"
So I declared a class (not taking left and right to keep thigs simple):
class Num n => Moving p n where
up' :: n -> p -> p
down' :: n -> p -> p
up' n = down' (-n)
down' n = up' (-n)
And an instance of Moving for Point a data type:
instance Num a => Moving (Point a) a where
up' n (Point x y) = Point x (y - n)
But when I try to use it, I got an error:
✗ ghci ./uno.hs
GHCi, version 7.10.3: http://www.haskell.org/ghc/ :? for help
[1 of 1] Compiling Main ( uno.hs, interpreted )
Ok, modules loaded: Main.
*Main> let p = Point { pointX = 0, pointY = 0 }
*Main> up' 10 p
<interactive>:3:1:
Non type-variable argument in the constraint: Moving (Point a) n
(Use FlexibleContexts to permit this)
When checking that ‘it’ has the inferred type
it :: forall n a. (Num a, Moving (Point a) n) => Point a
And the thing that confuses me much: I put the FlexibleContexts pragma to the pragma listing in the head, but ghcu still suggest me to get it included.
How can I fix my class / instance to get parametric polymorphism working? :)
And the thing that confuses me much: I put the FlexibleContexts pragma to the pragma listing in the head, but ghcu still suggest me to get it included.
This only enables the extension in the module itself. To write this code in GHCi, you need to enable the extension in GHCi: :set -XFlexibleContexts.
But this is only part of the problem. It looks like for your class p should determine n: you can only move a Point a up and down by a, right? But as it stands, nothing stops you from defining more Moving (Point a) SomeOtherType instances, and the compiler doesn't assume you won't. So a and n in the inferred type are completely unrelated, where you want them to be the same. This can be fixed by adding the FunctionalDependencies extension and changing the class declaration to say
class Num n => Moving p n | p -> n where
which means exactly that there can't be instances with same p and different n.
I think that's enough to make it work. The code will still be underdetermined because it allows any numeric a, but defaulting rules will pick Integer.

IEEE floating point signalling NaN (sNaN) in Haskell

Is there any way to define signaling NaN in Haskell? I found two approaches to deal with NaNs:
1) use 0/0, which produces quite nan
2) package Data.Number.Transfinite, which has no signaling NaNs too.
PS Is there any way to put Word64 bit by bit into Double without writing C library?
I have found one non-portable way:
{-# LANGUAGE ForeignFunctionInterface #-}
import Data.Word (Word64, Word32)
import Unsafe.Coerce
import Foreign
import Foreign.C.Types
foreign import ccall "fenv.h feenableexcept" -- GNU extension
enableexcept :: CInt -> IO ()
class HasNAN a where
signalingNaN :: a
quietNaN :: a
instance HasNAN Double where
signalingNaN = unsafeCoerce (0x7ff4000000000000::Word64)
quietNaN = unsafeCoerce (0x7ff8000000000000::Word64)
instance HasNAN Float where
signalingNaN = unsafeCoerce (0x7fa00000::Word32)
quietNaN = unsafeCoerce (0x7fc00000::Word32)
main = do
enableexcept 1 -- FE_INVALID in my system
print $ show $ 1 + (quietNaN :: Float) -- works
print $ show $ 1 + (signalingNaN :: Float) -- fails
which perfectly fails. It turned out that FPU exceptions are a bad idea for Haskell. They are disabled by default for a good reason. They are OK if you debug C/C++/something else in gdb. I don't want to debug Haskell core dumps due to its non-imperative nature. Enabling FE_INVALID exceptions causes 0/0 and add to NaNs in Data.Number.Transfinite and GHC.Real to crash. But 0/0 calculated before enableexcept doesn't produce exceptions in addition.
I will use some simple errors check in my task. I need sNaN in just one place.
What about using Data.Maybe?
You would use Maybe Float as datatype (assuming you want to use Float), and Just x for the non-NaN value x, whereas Nothing would represent NaN.
However, you'd need to radd at least a Num instance to be able to calculate using Maybe Float instead of Float. You can use fromJust as an utility function for this.
Whether this is expressed as qNaN or sNaN entirely depends on your implementation.
You could use custom operators instead of custom types like this (this avoids replacing any Float in your code`)
snanPlus :: Float -> Float -> Float
snanPlus a b = if isNaN(a) then error "snan"
else if isNaN(b)
then error "snan"
else a + b
-- Some testing code
main = do
print $ 3.0 `snanPlus` 5.0 -- 8.0
print $ (0/0) `snanPlus` 5.0 -- error
The second print triggers the error.
Note: I'm not sure if there is a better way of formatting this, and you should probably not use concrete types in the function signature.
You can use Data.Ratio to produce Nan/Infinity by using the ratios 1/0 (infinity) or 0/0 (NaN).
A faster but less portable approach is to use GHC.Real which exports infinity and notANumber.
infinity, notANumber :: Rational
infinity = 1 :% 0
notANumber = 0 :% 0
Usage:
Prelude Data.Ratio GHC.Real> fromRational notANumber :: Float
NaN
For checking NaN/infinity, Prelude has two functions isNaN and isInfinite.
You can do something like this:
newtype SNaN a = SNaN { unSNaN :: a}
liftSNaN :: RealFloat a => (a -> a) -> (SNaN a -> SNaN a)
liftSNaN f (SNaN x)
| isNaN x = error "NaN"
| otherwise = SNaN . f $ x
liftSNaN' :: RealFloat a => (a -> b) -> (SNaN a -> b)
liftSNaN' f (SNaN x)
| isNaN x = error "NaN"
| otherwise = f $ x
liftSNaN2 :: RealFloat a => (a -> a -> a) -> (SNaN a -> SNaN a -> SNaN a)
liftSNaN2 f (SNaN x) (SNaN y)
| isNaN x || isNaN y = error "NaN"
| otherwise = SNaN $ f x y
liftSNaN2' :: RealFloat a => (a -> a -> b) -> (SNaN a -> SNaN a -> b)
liftSNaN2' f (SNaN x) (SNaN y)
| isNaN x || isNaN y = error "NaN"
| otherwise = f x y
instance RealFloat a => Eq (SNaN a)
where (==) = liftSNaN2' (==)
(/=) = liftSNaN2' (/=)
instance RealFloat a => Ord (SNaN a)
where compare = liftSNaN2' compare
(<) = liftSNaN2' (<)
(>=) = liftSNaN2' (>=)
(>) = liftSNaN2' (>)
(<=) = liftSNaN2' (<=)
max = liftSNaN2 max
min = liftSNaN2 min
instance (Show a, RealFloat a) => Show (SNaN a)
where show = liftSNaN' show
instance RealFloat a => Num (SNaN a)
where (+) = liftSNaN2 (+)
(*) = liftSNaN2 (*)
(-) = liftSNaN2 (-)
negate = liftSNaN negate
abs = liftSNaN abs
signum = liftSNaN signum
fromInteger = SNaN . fromInteger
instance RealFloat a => Fractional (SNaN a)
where (/) = liftSNaN2 (/)
recip = liftSNaN recip
fromRational = SNaN . fromRational
You'd need more type classes to get the full Float experience of course, but as you can see it's pretty easy boilerplate once the liftSNaN* functions are defined. Given that, the SNaN constructor turns a value in any RealFloat type into one that will explode if it's a NaN and you use it in any operation (some of these you might arguably want to work on NaNs, maybe == and/or show; you can vary to taste). unSNaN turns any SNaN back into a quiet NaN type.
It's still not directly using the Float (or Double, or whatever) type, but if you just change your type signatures pretty much everything will just work; the Num and Show instances I've given mean that numeric literals will just as easily be accepted as SNaN Float as they will be Float, and they show the same too. If you get sick of typing SNaN in the type signatures you could easily type Float' = SNaN Float, or even:
import Prelude hiding (Float)
import qualified Prelude as P
type Float = SNaN P.Float
Though I'd bet that would cause confusion for someone eventually! But with that the exact same source code should compile and work, provided you've filled in all the type classes you need and you're not calling any other code you can't modify that hard-codes particular concrete types (rather than accepting any type in an appropriate type class).
This is basically an elaboration on Uli Köhler's first suggestion of providing a Num instance for Maybe Float. I've just used NaNs directly to represent NaNs, rather than Nothing, and used isNan to detect them instead of case analysis on the Maybe (or isJust).
The advantages of using a newtype wrapper over Maybe are:
You avoid introducing another "invalid" value to the doing (Just NaN vs Nothing), that you have to worry about when converting to/from regular floats.
Newtypes are unboxed in GHC; an SNaN Float is represented at runtime identically to the corresponding Float. So there's no additional space overhaead for the Just cell, and converting back and forth between SNaN Float and Float are free operations. SNaN is just a tag that determines whether you would like implicit "if NaN then explode" checks inserted into your operations.

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)

Resources