Ink by Example: Functions

Functions are the building blocks of Ink and enable us to write terse functional code.

std := load('../vendor/std')
log := std.log


Functions are created with the arrow => symbol.

shout := (word) => word + '!'
log(shout('Hello'))

multiply := (x, y) => x * y
log(multiply(2, 8))

When a group of expressions follow the arrow symbol, the result of the final expression is the return value.

` single argument parentheses are optional`
sayAndMultiply := num => (
    log('About to multiply ' + string(num) + ':')

    ` the return value `
    num * num
)
log(sayAndMultiply(8))

Function invocation () takes precedence over property-access . — instead of obj.func(argument), we use (obj.func)(argument).

math := {
    swapSign: n => 0 - n
}
weight := (math.swapSign)(100)
log(weight)

Here's an example of tail recursion.

factorial := n => n :: {
    0 -> 1
    _ -> n * factorial(n-1)
}
log(factorial(5))

It's natural to use closures — functions that have access to the parent scope after the parent function has closed.

makeMultiplier := x => (
    y := y => x * y
)
multiplySeven := makeMultiplier(7)
multiplyTwenty := makeMultiplier(20)
log(multiplySeven(2))
log(multiplyTwenty(4))

Functions that immediately evalute and return another function is called currying in functional programming land.

greeting := a => b => a + ' ' + b
message := greeting('Hello there,')('General Kenobi')
log(message)

$ ink functions.ink
Hello!
16
About to multiply 8:
64
-100
120
14
80
Hello there, General Kenobi

Next example: Files.