hm-def-light
v0.1.4
Published
Runtime Hindley-Milner ad hoc type checking with Sanctuary
Downloads
4
Readme
Javascript runtime Hindley-Milner ad hoc type checking with Sanctuary.
Overview
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
Features
- 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
- Install
hm-def-light
withnpm
- or by any preferred means. - Then you're ready to go! Please, follow the examples for further apprehension.
API
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 TypeClass
es, 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 ({
checkTypes,
env : customEnv
})
const def = $create ({
create,
env : customEnv,
$ : SDef,
Z,
checkTypes,
typeClasses : [MyCustomTypeClass],
typeConstructors : {MyCustomType} // `Unary` and `Binary` type constructors are sensible here
})
// ...
Running tests:
For more information, I recommend a stride around the referenced resources.
License
This project is licensed under the MIT License - see the LICENSE file for details