2015-05-01
Yet another thing I often wish for in Erlang is staged application of any function without having to manually wrap it in stage funs (which you get in languages that feature curried-by-default functions, like OCaml and Haskell).
A few days ago it occurred to me that the ability to get fun arity info and to apply arguments as a list was all that was needed to get very, very close to the behavior I wanted. Voila:
-module(function). -export([curry/1]). curry(F) -> Info = erlang:fun_info(F), {value, {arity, Arity}} = lists:keysearch(arity, 1, Info), curry(F, [], Arity). curry(F, Args, 0) -> apply(F, lists:reverse(Args)); curry(F, Args, Arity) -> fun (X) -> curry(F, [X | Args], Arity - 1) end.In action:
$ erl 1> 1> Nums = lists:seq(1, 10). [1,2,3,4,5,6,7,8,9,10] 2> 2> Plus = function:curry(fun (X, Y) -> X + Y end). #Fun3> 3> lists:map(Plus(1), Nums). [2,3,4,5,6,7,8,9,10,11] 4> 4> lists:map(Plus(3), Nums). [4,5,6,7,8,9,10,11,12,13] 5> 5> lists:map(Plus(5), Nums). [6,7,8,9,10,11,12,13,14,15] 6> 6> Fold = function:curry(fun lists:foldl/3). #Fun 7> 7> AddTo = Fold(fun (X, Y) -> X + Y end). #Fun 8> 8> AddTo0 = AddTo(0). #Fun 9> 9> AddTo100 = AddTo(100). #Fun 10> 10> AddTo0(Nums). 55 11> AddTo100(Nums). 155 12> 12> AddTo100(lists:seq(4, 78)). 3175 13>
My implementation of curry/1
now lives in the
hope
library's hope_fun
module. See:
https://github.com/xandkar/hope/commit/e033aadea66cc7f68e3a66cde23a2edfe4c4e9e6
Now I've already gotten shots fired at me by the venerable ROK for wanting to do such things in Erlang (which I believe I adequately defended), but I'll be happy to read any other critiques - shoot me an email! :)