← Back to lessons

30 Function types

Intermediate

Functions have a type in Cangjie. Therefore we can create variables with function type and pass them to the functions.

Function type is created like this: f:(T1,T2,T3,T4) -> T5 Where T1,T2,…T5 are some types. It means that function f takes in 4 arguments of the corresponding types and return one value of type T5.

Map takes in one function and array of numbers. It then proceeds to apply this function to every number in the array. function type is (Int64)->Int64, so we pass single value of the array, and assign it the return value of the function.

Filter takes in one function and array of numbers. Type of the function is (T)->Bool, where T is type variable. It means that given value:T, it determines whether to keep it in the new ArrayList, or not based on the Bool return value.

We can declare variables that are of function type. The type of f is (Int64)->Int64, so it takes in one int and returns another integer.

We can map this function over the array nums.

We can also create the function in the function call using lambdas.

Because filter is a generic function, it can also work on strings.

Function types can be infered by a compiler from the function definition.

Here we use function composition that is a part of cangjie. Lets assume that we have a functions A:(T1)->T2, B: (T2)->T3. Instead of doing {x:T1 => B(A(x))}, we can do A~>B. This creates composed function. REMEMBER ORDER MATTERS!

function_type.cj
import std.collection.*

func map(function: (Int64) -> Int64, arr: Array<Int64>): Unit {
    for (i in 0..arr.size) {
        arr[i] = function(arr[i])
    }
}

func filter<T>(function: (T) -> Bool, arr: Array<T>): ArrayList<T> {
    var ans = ArrayList<T>()
    for (i in 0..arr.size) {
        if (function(arr[i])) {
            ans.append(arr[i])
        }
    }
    return ans
}

main() {
    var nums = Array<Int64>([1, 5, 2, 40, 123, 34])

    var f: (Int64) -> Int64 = {
        x: Int64 => if (x % 2 == 0) {
            x / 2
        } else {
            3 * x + 1
        }
    }

    map(f, nums)

    for (i in nums) {
        print("${i} ")
    }
    println()

    var Filtered = filter({x: Int64 => x >= 20}, nums)

    for (i in Filtered) {
        print("${i} ")
    }
    println()

    var strings = Array<String>(["Ali", "Maks", "Isaac", "Wiktoria", "Mateo"])

    var FilteredStrings = filter({x: String => x > "Lovely"}, strings)

    for (i in FilteredStrings) {
        println(i)
    }

    let f1 = {
        x: Int64 => x * 2
    }

    let f2 = {
        x: Int64 => x + 3
    }

    let arr1 = Array<Int64>([1, 69, 420, 2137])
    let arr2 = Array<Int64>([1, 69, 420, 2137])

    map(f1 ~> f2, arr1)
    map(f2 ~> f1, arr2)

    for (i in arr1) {
        print("${i} ")
    }
    println()
    for (i in arr2) {
        print("${i} ")
    }
    println()
}

// OUTPUT:
// 4 16 1 20 370 17 
// 20 370 
// Maks
// Wiktoria
// Mateo
// 5 141 843 4277 
// 8 144 846 4280