Multiple items
union case Probability.Probability: float -> Probability

--------------------
type Probability = | Probability of float

Full name: index.Probability
Multiple items
val float : value:'T -> float (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float

--------------------
type float = System.Double

Full name: Microsoft.FSharp.Core.float

--------------------
type float<'Measure> = float

Full name: Microsoft.FSharp.Core.float<_>
type bool = System.Boolean

Full name: Microsoft.FSharp.Core.bool
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
union case Option.None: Option<'T>
union case Option.Some: Value: 'T -> Option<'T>

Value constraint at compile-time

By Fahd Abdeljallal

What led me up to do this project ?

Introduction

  • Extension of DependentTypesProvider
  • Avoid incoherency in values both at compile and run-time
  • Hide boilerplate

Background -- Type Provider (TP)

  • Compiler extension
  • Grasp data from the outside world
  • Traverse the data in a type-safe manner, interactively

Why constraint in a TP?

  • Give meaning to a basic type, like:

    1: 
    
      type Probability = Probability of float
    
  • Have a set which follows a specific rule

The extension

  • Upper, Lower Constraint
  • Done only at runtime
  • Basic F# types

The extension : Upper, Lower Constraint (1)

  • Any constraint with generic rule
  • Fsi integrated takes string representation of a function of type

    1: 
    
      'a -> bool
    
  • Example

    1: 
    2: 
    
      let f (x:int) = 
          x % 5 = 0 
    

The extension : Upper, Lower Constraint (2)

  • Basic type has a validation rule inside himself

The extension : Done only at runtime

  • Compile-time constraint
  • Static method

    1: 
    2: 
    3: 
    
      type MultipleOf5 = Constraint.Numbers.ConstraintInt32<SomeValidationRule>
      let aValueFollowingTheRule = 5
      let value = MultipleOf5.Create<aValueFollowingTheRule>()
    
  • Problem : Only working with Literals / Basic F# types

The extension : Basic F# types at compile-time

  • How about arrays/list ...?
  • static method + string representation + Fsi integrated

    1: 
    2: 
    3: 
    
      type Constraint = Constraint.ArrayOfNumber.ConstraintByteArray<Rule>
      let aValueFollowingTheRule = "[|5uy;6uy;7uy|]"
      let value = Constraint.Create<aValueFollowingTheRule>()
    
  • string representation = type-checked at compile-time

Constraint little world

  • Provided Type world = secured by a validation system

     1: 
     2: 
     3: 
     4: 
     5: 
     6: 
     7: 
     8: 
     9: 
    10: 
    11: 
    12: 
    13: 
    14: 
    
      let rule = "let f (x:float) = x<>0. \nf"
      type NotZero = Constraint.Numbers.ConstraintDouble<rule>
    
      let divide (aFloat:float) (nonZeroFloat:NotZero) =
          aFloat / nonZeroFloat.RawValue
    
      let floatFromExternal = getFloatExternal()
      let maybeNotZeroFloat = NotZero.TryCreate(floatFromExternal)
    
      match maybeNotZeroFloat with
      |None -> // Do whatever : can't call divide function
    
      // This is going to be safe, Normally :D 
      |Some nonZeroFloat -> divide 5 nonZeroFloat
    

Demo

What's next?

  • Add some other types if needed
  • Operations between these types ?

Question

Any Questions ?