
Is there a standard Haskell trick for checking run-time assignment to data types? I'd like a data type of Probability that ensures its Double argument is between 0 and 1.
Jim
A fairly common technique to achieve this is smart constructors (apparently also called factory functions). http://www.haskell.org/hawiki/FactoryFunction You simply enforce the invariant on construction. For your example, it would look like, newtype Probability = Probability Double probability p | 0.0 <= p && p <= 1.0 = Probability p unProbability (Probability p) = p Simply don't export Probability's constructor and it will be impossible to create a Probability with a value outside of [0,1]. However, you may want to export the constructor, or alternatively, export a function with a name like unsafeProbability (= Probability) for situations where you can statically decide that the invariant will hold if the superfluous checking costs too much, which doesn't seem particularly likely in this case. Providing a function of type Double -> Maybe Probability is also likely a good idea.

You can also do this in a way that statically guarantees the property... First you need to lift the numeric argument to the type level... This is harder for a double than an integer, but not impossible... First convert the double to a pair of Integers (an infintite precision rational number)... Then each Integer can be represented as a uniary number (this is the simplest but you will run out of context reduction stack on any kind of real number, so binary or decimal representation is better). The definitions required for this are in the attached library. class Rat x -- class of type level rationals instance (Number x,Number x) => Rat (x,x) Now the specific class: class Rat0to1 r instance Div x y Zero => Rat0to1 (x,y) -- gives range 0.0000 -> 0.9999 instance (Div x y (Suc Zero),Mod x y Zero) => Rat0to1 (x,y) -- gives 1.0000 -> 1.0000 an exmaple function applying the constraint: rat0to1 :: Rat0to1 => r -> r rat0to1 = id The constraint can be converted from a static constraint to a runtime constraint by using existentials: data Ext0to1 = forall x y . (Number x,Number y,Rat0to1 (x,y)) => Ext0to1 (x,y) Keean. Derek Elkins wrote:
Is there a standard Haskell trick for checking run-time assignment to data types? I'd like a data type of Probability that ensures its Double argument is between 0 and 1.
Jim

On Wed, Dec 08, 2004 at 11:11:44AM +0000, Keean Schupke wrote:
You can also do this in a way that statically guarantees the property...
First you need to lift the numeric argument to the type level... This is harder for a double than an integer, but not impossible... First convert the double to a pair of Integers (an infintite precision rational number)... Then each Integer can be represented as a uniary number (this is the simplest but you will run out of context reduction stack on any kind of real number, so binary or decimal representation is better). The definitions required for this are in the attached library.
Alternatively, you could just use atan or erfc to map between the complete set of real numbers and the range from 0 to 1. This sort of trick is sometimes helpful to convert a constrained minimization into an unconstrained one. -- David Roundy http://www.darcs.net
participants (3)
-
David Roundy
-
Derek Elkins
-
Keean Schupke