Rebol [
    Title: "Curry"
    Date: 10/12/1999
    Version: 2.0.1
    File: %curry.r
    Author: "Ladislav Mecir"
    Email: [EMAIL PROTECTED]
    Comment: {
        The former version had the following limitations:
        1. incompatibility with CATCH and THROW attributes in the argument
function
        2. incompatibility with refinements in the argument function
        3. incompatibility with literal or fetched arguments in the argument
function
        4. incompatibility with argument functions with one of the following
arguments:
            SET, DO, APPEND, COPY, F, FORMARGS, ARGS, REDARGS, RESTARGS
        5. didn't handle correctly natives and actions
        6. didn't handle correctly functions with local variables
        7. The argument function's code has been unnecessarily copied

        The limitations 4 to 7 are gone now, limitations 1 to 3 are still
valid.

        The meaning of the ARGS argument has changed.
        ARGS is now an INTEGER! - see below

        The error checking is gone for now, but I will add it next time...
    }
]

; some helper functions
map: func ["Maps a function to all elements of a block"
    f [any-function!] blk [block!] /local result
][
    result: make block! length? blk
    foreach elem blk [
        append/only result f :elem
    ]
    result
]

enum: func ["Creates a block of integers"
    from [integer!]
    to [integer!]
    /local result
] [
    result: make block! 1 + to - from
    for i from to 1 [
        append result i
    ]
    result
]

ao: func [block [block!] value] [
    head insert/only tail copy block value
]

ac: func [block1 [series!] block2 [series!]] [
    append copy block1 block2
]

toarg: func [i [integer!]] [to-word ac "a" form i]

tga: func [i [integer!]] [to-get-word to-word ac "a" form i]

nargs: func ["The number of the function arguments"
    f [any-function!]
] [
    result: 0
    ptr: first :f
    while [not tail? ptr] [
        either refinement? first :ptr [ptr: tail ptr] [
            result: result + 1
            ptr: next ptr
        ]
    ]
    result
]

; Although strange, it is much needed
apply: func ["Apply a function to it's arguments"
    f [any-function!]
    blkargs [block!] "Argument values"
    /local args
] [
    args: map :toarg enum 1 length? blkargs
    use args [
        args: bind args 'a1
        set args blkargs
        args: map :to-get-word args
        args: bind args 'a1
        do ac [f] args
    ]
]

curry: func ["Create curried functions"
    f [any-function!] "Function to be curried"
    args [integer!] "Number of the arguments of the result"
] [
    func map :toarg enum 1 args ao [
        apply func [f args] [
            function map :toarg enum args + 1 nargs :f [y] ao [
                apply function [f args redargs] [redrest] [
                    redrest: reduce bind map :tga enum args + 1 nargs :f 'y
                    apply :f ac redargs redrest
                ]
            ] reduce [:f :args reduce bind map :tga enum 1 args 'a1]
        ]
    ] reduce [:f :args]
]

curryfirst: func [f [any-function!]] [curry :f 1]

;**********end of %curry.r

f: func [x y] [reduce [x y]]
cfx: curryfirst :f

Examples:
>> f: func [x y] [reduce [x y]]
>> cfx: curryfirst :f
>> cf777: cfx 777
>> cf777 4
== [777 4]
>> cf5: cfx 5
>> cf777 8
== [777 8]
>> cf5 6
== [5 6]
>> curryadd: curryfirst :add
>> ca1: curryadd 1
>> ca2: curryadd 2
>> ca1 1
== 2
>> ca2 1
== 3
>> ca2 3
== 5
>> ca1 4
== 5
>> capp: curryfirst :apply
>> cappt: capp :type?
>> cappt reduce [:odd?]
== action!
>> composition: curry func [f [any-function!] g [any-function!] x] [f g :x]
2
>> cf: composition func [x] [x + 1] func [x] [10 * x]
>> cf 1
== 11
>> mapper: curry :map 1
>> oddm: mapper :odd?
>> oddm [1 2 3 4 5 6]
== [true false true false true false]

Reply via email to