From a08e3ff4557ad9d77369f29b4a700f7e14ea23da Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Mon, 20 May 2013 16:20:31 +1000 Subject: [PATCH] Add curry! macro --- src/libsyntax/ext/expand.rs | 49 ++++++++++++++++++++++++++++++++ src/test/run-pass/curry-macro.rs | 28 ++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 src/test/run-pass/curry-macro.rs diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f9ca84473fb3c..db588f3a99a75 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -577,6 +577,55 @@ pub fn core_macros() -> ~str { $(if $pred $body)else+ ); ) + + // + // Declares a named or anonymous curried function. + // + // # Example + // + // ~~~ + // curry!( + // fn mul(x: int, y: int) -> int { + // x * y + // } + // ) + // + // assert_eq!(mul(2)(3), 6); + // + // let mul2 = mul(2); + // assert_eq!(mul2(3), 6); + // + // let f: @fn(int) -> @fn(int) -> int = curry!(|x,y| x * y); + // assert_eq!(f(2)(3), 6); + // ~~~ + // + // # Notes: + // + // - It would be nicer if the syntax for named declarations could be + // `fn foo x: int -> y: int -> int` to reinforce the curried nature of the + // resulting function, but this causes an ambiguity during macro expansion. + // - Unfortunately generics and lifetimes are not supported due to the + // difficulty of implementing type parameter lists in macros. + // - Anonymous curried functions have difficulty inferring types. + // + macro_rules! curry( + // named curried function + (fn $fn_name:ident ($arg:ident : $arg_ty:ty, + $($arg_rest:ident : $arg_rest_ty:ty),*) + -> $ret_ty:ty $fn_body:expr + ) => ( + fn $fn_name($arg: $arg_ty) $(-> @fn($arg_rest: $arg_rest_ty))* -> $ret_ty { + curry!(|$($arg_rest),*| $fn_body ) + } + ); + // anonymous curried function + (|$arg:ident, $($arg_rest:ident),*| $fn_body:expr) => ( + |$arg| curry!(|$($arg_rest),*| $fn_body) + ); + (|$arg:ident| $fn_body:expr) => ( + |$arg| $fn_body + ); + ) }"; } diff --git a/src/test/run-pass/curry-macro.rs b/src/test/run-pass/curry-macro.rs new file mode 100644 index 0000000000000..f2b790ee30d33 --- /dev/null +++ b/src/test/run-pass/curry-macro.rs @@ -0,0 +1,28 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +curry!( + fn mul(x: int, y: int, z: int) -> int { + x * y * z + } +) + +fn main() { + assert_eq!(mul(2)(3)(2), 12); + + let mul2 = mul(2); + assert_eq!(mul2(3)(2), 12); + + // type error :( + // assert_eq!(curry!(|x,y,z| x * y * z)(2)(3)(2), 12); + + let local_mul: @fn(int) -> @fn(int) -> @fn(int) -> int = curry!(|x,y,z| x * y * z); + assert_eq!(local_mul(2)(3)(2), 12); +}