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 defnSignature 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 '[*]' # falsefn.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] # falsefn.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