npm i hm-def-light


Javascript runtime Hindley-Milner ad hoc type checking with Sanctuary

by leosbotelho

0.1.4 (see all)License:MITTypeScript:Not Found
npm i hm-def-light

Javascript runtime Hindley-Milner ad hoc type checking with Sanctuary.


It's basically a syntax sugar over sanctuary-def, inspired on hm-def.

"It facilitates the definition of curried JavaScript functions which are explicit about the number of arguments to which they may be applied and the types of those arguments." - sanctuary-def


  • All Sanctuary's type constructors and type classes available out of the box.
  • Supports custom type constructors and type classes.
  • Only three dependencies: Sanctuary, Parsimmon and hm-lang-light.
  • Comprehensively tested - works with any Sanctuary type declaration.
  • Input is fairly validated.
  • Written in a -quite- functional Javascript idiom.

Getting Started

  1. Install hm-def-light with npm - or by any preferred means.
    • For testing, it's sufficient to install the dev dependencies and run the test script.
    • It's dependent on imports. So, adopt it - with e.g: esm, babel.
  2. Then you're ready to go! Please, follow the examples for further apprehension.


hm-def-light is reliant on:

create           : S create
env              : S env
$                : sanctuary-def
Z                : sanctuary-type-classes
checkTypes       : Boolean
typeClasses      : optional [TypeClass]
typeConstructors : optional StrMap Type'

Params 1-5 are not checked for correctness: they're supposed to be correct.
Type' is a -fancy, uncanon- alias for $ Nullary, Unary and Binary types.

One by one brief:

create           : for internal S retrieval
env              : basis for `Type'`s (e.g: `Number`, `HtmlElement`, `Error` etc)
$                : for `Type`s construction
Z                : basis for default `TypeClasses` (e.g: `Functor`, `Alt`, `Traversable` etc)
checkTypes       : "The checkTypes option determines whether type checking is enabled. 
                    This allows one to only pay the performance cost of run-time type checking  
                    during development."
typeClasses      : optional custom `TypeClass`es
typeConstructors : optional custom `Type'`s; * must also be defined in the environment (i.e env)

Hands on:

First define a def function for the setting:

import {create, env}  from "sanctuary"
import SDef           from "sanctuary-def"
import Z              from "sanctuary-type-classes"

import $create        from "hm-def-light"

// checkTypes :: Boolean
const checkTypes = true

// minimal
const def = $create ({create, env, $ : SDef, Z, checkTypes})

Now you can use def in function definitions:

const add =
def ("add :: Number -> Number -> Number")
    (x => y => x+y)

add (1) (2) // ok
add (3) (4) // ok

add ("a") ("b") // error - in case of checkTypes = true
add ("c") ("d") // error ...

As a design choice, def is not memoized.
So you should be attentious to repeated def calls:

while (true) {
  // this repeats the entire, sanctuary-def `def`, 'mirroring' for every iteration
  def ("K :: a -> b -> a")
      (x => y => x)

In this case, the function definition could be taken out of the loop.
Alternatively, it's very easy to memoize def yourself:

// e.g
const memoDef = def => memo =>
  memo (typeDeclaration => def (typeDeclaration))

minimal def also works for more complex type signatures:

const ex1 =
def ("ex1 :: (Foldable a, Alternative a) => a -> a")
    (x => x)

ex1 (1)   // error
ex1 ([])  // ok

const ex2 =
def ("ex2 :: Maybe a -> Either String a")
    (x => maybeToEither ("dummy") (x))

ex2 (Just (1))    // Right (1)
ex2 (Nothing)     // Left  ("dummy")
ex2 ("arbitrary") // error

const ex3 =
def ("ex3 :: NonEmpty [Number] -> Number")
    (arr => arr[0])

ex3 ([1,2]) // ok
ex3 ([])    // error

// ...

And if you need custom Type's or TypeClasses, there's no secret, e.g:

const customEnv = env.concat ([MyCustomType (SDef.Date)]) // `Type` in env is mandatory
                                                          // But it can be refined as 
                                                          // required: no need to pass
                                                          // `Unknown`s if not desired,
                                                          // thus retaining `env` 
                                                          // characteristics

const S = create ({
  env : customEnv

const def = $create ({
  env              : customEnv, 
  $                : SDef, 
  typeClasses      : [MyCustomTypeClass],
  typeConstructors : {MyCustomType} // `Unary` and `Binary` type constructors are sensible here

// ...

Running tests:
bash test results ilustration

For more information, I recommend a stride around the referenced resources.


This project is licensed under the MIT License - see the LICENSE file for details

No alternatives found
No tutorials found
Add a tutorial
No dependencies found

Rate & Review

No reviews found
Be the first to rate