defn v0.2.0
defn 
defn
is a used to define/overload functions with type signature. It uses type-check
for choosing the signature that matches the arguments, and type-precedence
to choose the most specific signature.
$ npm install defn
Signature definition
defn
supports all the types that can be checked with type-check
for arguments signature. It assumes that the signature is a tuple, but the pharantesis are not required. So, (Number, Number)
and Number, Number
are equivalent. However, a special type notation is added, ...Type
, which means that all the arguments are of type Type
(...
matches any arguments with any type). So, here are few examples of signatures:
...
(translates to[*]
) - matches anything...String
(translates to[String]
) - matchesf(\a)
,f(\a, \b)
, etc[*]
(translates to([*])
) - matchesf([1 2 3])
, but doesn't matchf(1, 2, 3)
Number | String
- matchesf(1)
orf(\a)
, but notf(1, \a)
{x: Number, y: Number}
- matchesf({x: 1, y: 1})
Usage
require! \defn
fn = defn \String, (s) -> "#s is a string"
fn.overload \Number, (n) -> "#n is a number"
fn \s # "s is a string"
fn 1 # "1 is a number"
defn(fn-impl)
Defines a function with a implementation without a signature (assumes ...
as default)
fn = defn -> it
fn 1 # 1
fn \a # 'a'
defn(signature, fn-impl)
Defines a function with an implementation having the provided signature
fn = defn \String -> '#it is a string'
fn \a # 'a is a string'
fn 1 # throws Error - Can't call on 1: fn requires one of (String)
defn(definitions)
Defines a function with multiple signatures
{fold, reject} = require \prelude-ls
diff = defn do
'Number, Number': (a, b) -> a - b
'[Number], Number': (list, item) -> reject (is item), list
'[Number], [Number]': (list, sublist) -> fold diff, list, sublist
diff 1, 2 # -1
diff [1 2 3 1], 1 # [2 3]
diff [1 2 3 1], [1 2] # [3]
fn.overload(...)
Same usage as for defn(...)
fn = defn -> 'default'
fn.overload '...String' -> 'string args'
fn \a, \b # 'string'
fn [1 2] # 'default'
fn.signatures()
Returns all signatures defined for the function
fn = defn do
'...' -> 'default'
'{x: *, y: *}' -> 'x:y'
'Number, Number' -> 'n,n'
fn.signatures! # ['[*]' '({x: *, y: *})' '(Number, Number)']
fn.has-signature(sig)
Checks that a certain signature is defined for fn
fn = defn -> 'default'
fn.overload \String -> '#it is a string'
fn.has-signature '...' # true
fn.has-signature 'String' # true
fn.has-signature '(String)' # true
fn.has-signature '[*]' # false
fn.can-call(args)
Returns true if the arguments args
can be called on fn
fn = defn \Number -> 0
fn.can-call 1 # true
fn.can-call 1, 2 # false
fn.can-call [1] # false
fn.call(...), fn.apply(...)
Overriden Function
methods. Will point to the implementation matched by the provided arguments
fn = defn \Number -> @.number + it
fn.overload \String -> @.string + it
obj = number: 1, string: \s
fn.call obj, 20 # 21
fn.apply obj, [\tring] # 'string'
Misc
Chains
defn
and overload
are chainable:
fn = defn -> 'default'
.overload \String -> 's'
.overload \Number -> 0
fn.signatures! # ['[*]' '(String)' '(Number)']
Defs Overwrites
If a signature gets another implementation, it overwrites the previous
fn = defn -> 'default'
fn.overload -> 'the new default'
fn! # 'the new default'
Signature precedence
The order in which the signatures are defined is irelevant: the most specific signature for the given arguments is chosen each time, using type-precedence
:
fn = defn do
'...' -> default
\Array -> 'a generic array'
'[Number]' -> 'an array of numbers'
fn [1 2] # 'an array of numbers'
fn [\a \b] # 'a generic array'
fn {x: 1} # 'default'
12 years ago