Is it possible to implement auto-currying to the Lisp-family languages? - clojure

That is, when you call a function with >1 arity with only one argument, it should, instead of displaying an error, curry that argument and return the resulting function with decreased arity. Is this possible to do using Lisp's macros?

It's possible, but not easy if you want a useful result.
If you want a language that always does simple currying, then the implementation is easy. You just convert every application of more than one input to a nested application, and the same for functions of more than one argument. With Racket's language facilities, this is a very simple exercise. (In other lisps you can get a similar effect by some macro around the code where you want to use it.)
(Incidentally, I have a language on top of Racket that does just this. It gets the full cuteness of auto-curried languages, but it's not intended to be practical.)
However, it's not too useful since it only works for functions of one argument. You could make it useful with some hacking, for example, treat the rest of the lisp system around your language as a foreign language and provide forms to use it. Another alternative is to provide your language with arity information about the surrounding lisp's functions. Either of these require much more work.
Another option is to just check every application. In other words, you turn every
(f x y z)
into code that checks the arity of f and will create a closure if there are not enough arguments. This is not too hard in itself, but it will lead to a significant overhead price. You could try to use a similar trick of some information about arities of functions that you'd use in the macro level to know where such closures should be created -- but that's difficult in essentially the same way.
But there is a much more serious problem, at the highlevel of what you want to do. The thing is that variable-arity functions just don't play well with automatic currying. For example, take an expression like:
(+ 1 2 3)
How would you decide if this should be called as is, or whether it should be translated to ((+ 1 2) 3)? It seems like there's an easy answer here, but what about this? (translate to your favorite lisp dialect)
(define foo (lambda xs (lambda ys (list xs ys))))
In this case you can split a (foo 1 2 3) in a number of ways. Yet another issue is what do you do with something like:
(list +)
Here you have + as an expression, but you could decide that this is the same as applying it on zero inputs which fits +s arity, but then how do you write an expression that evaluates to the addition function? (Sidenote: ML and Haskell "solves" this by not having nullary functions...)
Some of these issues can be resolved by deciding that each "real" application must have parens for it, so a + by itself will never be applied. But that loses much of the cuteness of having an auto-curried language, and you still have problems to solve...

In Scheme it's possible to curry a function using the curry procedure:
(define (add x y)
(+ x y))
(add 1 2) ; non-curried procedure call
(curry add) ; curried procedure, expects two arguments
((curry add) 1) ; curried procedure, expects one argument
(((curry add) 1) 2) ; curried procedure call
From Racket's documentation:
[curry] returns a procedure that is a curried version of proc. When the resulting procedure is first applied, unless it is given the maximum number of arguments that it can accept, the result is a procedure to accept additional arguments.
You could easily implement a macro which automatically uses curry when defining new procedures, something like this:
(define-syntax define-curried
(syntax-rules ()
((_ (f . a) body ...)
(define f (curry (lambda a (begin body ...)))))))
Now the following definition of add will be curried:
(define-curried (add a b)
(+ a b))
add
> #<procedure:curried>
(add 1)
> #<procedure:curried>
((add 1) 2)
> 3
(add 1 2)
> 3

The short answer is yes, though not easily.
you could implament this as a macro that wrapped every call in partial, though only in limited context. Clojure has some features that would make this rather difficult such as variable arity functions and dynamit calls. Clojure lacks a formal type system to concretely decide when the call can have no more arguments and should actually be called.

As noted by Alex W, the Common Lisp Cookbook does give an example of a "curry" function for Common Lisp. The specific example is further down on that page:
(declaim (ftype (function (function &rest t) function) curry)
(inline curry)) ;; optional
(defun curry (function &rest args)
(lambda (&rest more-args)
(apply function (append args more-args))))
Auto-currying shouldn't be that hard to implement, so I took a crack at it. Note that the following isn't extensively tested, and doesn't check that there aren't too many args (the function just completes when there are that number or more):
(defun auto-curry (function num-args)
(lambda (&rest args)
(if (>= (length args) num-args)
(apply function args)
(auto-curry (apply (curry #'curry function) args)
(- num-args (length args))))))
Seems to work, though:
* (auto-curry #'+ 3)
#<CLOSURE (LAMBDA (&REST ARGS)) {1002F78EB9}>
* (funcall (auto-curry #'+ 3) 1)
#<CLOSURE (LAMBDA (&REST ARGS)) {1002F7A689}>
* (funcall (funcall (funcall (auto-curry #'+ 3) 1) 2) 5)
8
* (funcall (funcall (auto-curry #'+ 3) 3 4) 7)
14
A primitive (doesn't handle full lambda lists properly, just simple parameter lists) version of some macro syntax sugar over the above:
(defmacro defun-auto-curry (fn-name (&rest args) &body body)
(let ((currying-args (gensym)))
`(defun ,fn-name (&rest ,currying-args)
(apply (auto-curry (lambda (,#args) ,#body)
,(length args))
,currying-args))))
Seems to work, though the need for funcall is still annoying:
* (defun-auto-curry auto-curry-+ (x y z)
(+ x y z))
AUTO-CURRY-+
* (funcall (auto-curry-+ 1) 2 3)
6
* (auto-curry-+ 1)
#<CLOSURE (LAMBDA (&REST ARGS)) {1002B0DE29}>

Sure, you just have to decide exact semantics for your language, and then implement your own loader which will translate your source files into the implementation language.
You could e.g. translate every user function call (f a b c ... z) into (...(((f a) b) c)... z), and every (define (f a b c ... z) ...) to (define f (lambda(a) (lambda(b) (lambda(c) (... (lambda(z) ...) ...))))) on top of a Scheme, to have an auto-currying Scheme (that would forbid varargs functions of course).
You will also need to define your own primitives, turning the varargs functions like e.g. (+) to binary, and turning their applications to using fold e.g. (+ 1 2 3 4) ==> (fold (+) (list 1 2 3 4) 0) or something - or perhaps just making such calls as (+ 1 2 3 4) illegal in your new language, expecting of its user to write fold forms by themselves.
That's what I meant by "deciding ... semantics for your language".
The loader can be as simple as wrapping the file contents into a call to a macro - which you would then have to implement, as per your question.

Lisp already has Functional Currying:
* (defun adder (n)
(lambda (x) (+ x n)))
ADDER
http://cl-cookbook.sourceforge.net/functions.html
Here's what I was reading about Lisp macros: https://web.archive.org/web/20060109115926/http://www.apl.jhu.edu/~hall/Lisp-Notes/Macros.html
It's possible to implement this in pure Lisp. It's possible to implement it using macros as well, however it seems as though macros would make it more confusing for very basic stuff.

Related

Can one apply a macro to an argument list?

My goal is to be able to apply a macro to an argument list in the same way the apply primitive procedure applies a procedure to an argument list.
The list will already be evaluated at the time of application of the macro, there is no way around that and that’s fine; I am wondering if there is any way to programmatically “splice” the list into the macro application (in the same sense as with unquote-splicing). The difficulty resides in that one cannot pass the macro identifier as an argument.
One use case would be
(apply and list)
which would be equivalent to
(not (memq #f list))
to see if there is a #f in list.
Preferably this would be R7RS conformant.
One sort of hacky way would be (as suggested on reddit)
(eval (cons 'and list))
but this is not R7RS conformant, as eval must take an environment argument and it seems to me the standard doesn’t specify how to snatch the environment in effect at the call to eval.
Another half solution is the following, which only works if the list is given directly as a parenthesized sequence of values:
(syntax-rules ()
((_ identifier (val ...))
(identifier val ...)))
I'm posting this as a partial answer I found to my own question, and I'll accept it in a few days if nothing new pops up.
The following works, but only if the macro to apply is contained in a library.
(import (scheme base)
(scheme eval)
(scheme write))
(define (apply-macro mac args . libs)
(eval (cons mac args)
(apply environment libs)))
(define list '(#f #t #t #t))
(display (apply-macro 'and list '(scheme base))) ; => #f
(display (apply-macro 'and (cdr list) '(scheme base))) ; => #t
You can't do that; macros apply to syntax, transforming code fragments into other code fragments, not to values.
Even if you could do it, it would not be equivalent to applying and, since all the elements of list would be evaluated.
For instance, if you define the non-terminating procedure,
(define (forever) (forever))
then (and #f (forever)) is #f, but (apply and (list #f (forever))) would not terminate.
You cannot do this without eval. You would need to implement a procedure version of AND.
The reason it's impossible is because macro expansion is one phase and evaluation is a later phase. The list is piece of dynamic data existing only in the later phase, so a macro cannot use that.

Why does Lisp allow replacement of math operators in let?

I know in Scheme I can write this:
(let ((+ *)) (+ 2 3)) => 6
As well as this, in Clojure:
(let [+ *] (+ 2 3)) => 6
I know this can work, but it feels so weird. I think in any language, the math operators are predefined. C++ and Scala can do operator overloading, but this doesn't seem to be that.
Doesn't this cause confusion? Why does Lisp allow this?
This is not a general Lisp feature.
In Common Lisp the effects of binding a core language function is undefined. This means the developer should not expect that it works in portable code. An implementation may also signal a warning or an error.
For example the SBCL compiler will signal this error:
; caught ERROR:
; Lock on package COMMON-LISP violated when
; binding + as a local function while
; in package COMMON-LISP-USER.
; See also:
; The SBCL Manual, Node "Package Locks"
; The ANSI Standard, Section 11.1.2.1.2
; (DEFUN FOO (X Y)
; (FLET ((+ (X Y)
; (* X Y)))
; (+ X Y)))
We can have our own + in Common Lisp, but it then has to be in a different package (= symbol namespace):
(defpackage "MYLISP"
(:use "CL")
(:shadow CL:+))
(in-package "MYLISP")
(defun foo (a b)
(flet ((+ (x y)
(* x y)))
(+ a b)))
Disclaimer: This is from a Clojure point of view.
+ is just another function. You can pass it around and write sum with it, have partial application, read docs about it, ...:
user=> (apply + [1 2 3])
6
user=> (reduce + [1 2 3])
6
user=> (map (partial + 10) [1 2 3])
(11 12 13)
user=> `+
clojure.core/+
user=> (doc +)
-------------------------
clojure.core/+
([] [x] [x y] [x y & more])
Returns the sum of nums. (+) returns 0. Does not auto-promote
longs, will throw on overflow. See also: +'
So you can have many + in different namespaces. The core one get's "use"-ed for you by default, but you can simply write your own. You can write your own DSL:
user=> (defn + [s] (re-pattern (str s "+")))
WARNING: + already refers to: #'clojure.core/+ in namespace: user, being replaced by: #'user/+
#'user/+
user=> (+ "\\d")
#"\d+"
user=> (re-find (+ "\\d") "666")
"666"
It's not special form, it's nothing different from any other function. So with that established, why should it not be allowed to be overriden?
In Scheme you are making a local binding, shadowing whatever is higher, With let. Since + and * are just variables that just happen to evaluate to procedures you are just giving old procedures other variable names.
(let ((+ *))
+)
; ==> #<procedure:*> (non standard visualization of a procedure)
In Scheme there are no reserved words. If you look at other languages the list of reserved words are quite high. Thus in Scheme you can do this:
(define (test v)
(define let 10) ; from here you cannot use let in this scope
(define define (+ let v)) ; from here you cannot use define to define stuff
define) ; this is the variable, not the special form
;; here let and define goes out of scope and the special forms are OK again
(define define +) ; from here you cannot use top level define
(define 5 6)
; ==> 11
THe really nice thing about this is that if you choose a name and the next version of the standard happens to use the same name for something similar, but not compatible, your code will not break. In other languages I have worked with a new version might introduce conflicts.
R6RS makes it even easier
From R6RS we have libraries. That means that we have full control over what top level forms we get from the standard into our programs. You have several ways to do it:
#!r6rs
(import (rename (except (rnrs base) +) (* +)))
(+ 10 20)
; ==> 200
This is also OK.
#!r6rs
(import (except (rnrs base) +))
(define + *)
(+ 10 20)
; ==> 200 guaranteed
And finally:
#!r6rs
(import (rnrs base)) ; imports both * and +
(define + *) ; defines + as an alias to *
(+ 10 20)
; ==> 200 guaranteed
Other languages does this too:
JavaScript is perhaps the most obvious:
parseFloat = parseInt;
parseFloat("4.5")
// ==> 4
But you cannot touch their operators. They are reserved because the language needs to do a lot of stuff for the operator precedence. Just like Scheme JS is nice language for duck typing.
Mainstream Lisp dialects do not have reserved tokens for infix operations. There is no categorical difference between +, expt, format or open-file: they are all just symbols.
A Lisp proram which performs (let ((+ 3)) ...) is spiritually very similar to a C program which does something like { int sqrt = 42; ... }. There is a sqrt function in the standard C library, and since C has a single namespace (it's a Lisp-1), that sqrt is now shadowed.
What we can't do in C is { int + = 42; ...} which is because + is an operator token. An identifier is called for, so there is a syntax error. We also can't do { struct interface *if = get_interface(...); } because if is a reserved keyword and not an identifier, even though it looks like one. Lisps tend not to have reserved keywords, but some dialects have certain symbols or categories of symbols that can't be bound as variables. In ANSI Common Lisp, we can't use nil or t as variables. (Specifically, those symbols nil and t that come from the common-lisp package). This annoys some programmers, because they'd like a t variable for "time" or "type". Also, symbols from the keyword package, usually appearing with a leading colon, cannot be bound as variables. The reason is that all these symbols are self-evaluating. nil, t and the keyword symbols evaluate to themselves, and so do not act as variables to denote another value.
The reason we allow this in lisp is that all bindings are done with lexical scope, which is a concept that comes from lambda calculus.
lambda calculus is a simplified system for managing variable binding. In lambda calculus the rules for things like
(lambda (x) (lambda (y) y))
and
(lambda (x) (lambda (y) x))
and even
(lambda (x) (lambda (x) x))
are carefully specified.
In lisp LET can be thought of as syntactic sugar for a lambda expression, for example your expression (let ([+ x]) (+ 2 3)) is equivalent to ((lambda (+) (+ 2 3)) x) which according to lambda calculus simplifies down to (x 2 3).
In summary, lisp is based on uniformly applying a very simple and clear model (called lambda calculus). If it seems strange at first, that's because most other programming languages don't have such consistency or base their variable binding on a mathematical model.
Scheme's philosophy is to impose minimal restriction such that to give maximal power to programmer.
A reason to allow such things is that in Scheme you can embed other languages and in other languages you want to use the * operator with different semantics.
For example, if you implement a language to represent regular expressions you want to give the * the semantics of the algebraic kleene operator and write programs like this one
(* (+ "abc" "def") )
to represent a language that contain words like this one
empty
abc
abcabc
abcdef
def
defdef
defabc
....
Starting from the main language, untyped lambda calculus, it is possible to create a language in which you can redefine absolutely everything apart from the lambda symbol. This is the model of computation scheme is build on.
It's not weird because in lisp there are no operators except functions and special forms like let or if, that can be builtin or created as macros. So here + is not an operator, but a function that is assigned to symbol + that is adding its arguments (in scheme and clojure you can say that it's just variable that hold function for adding numbers), the same * is not multiplication operator but asterisk symbol that is multiplying its arguments, so this is just convenient notation that it use + symbol it could be add or sum but + is shorter and similar as in other languages.
This is one of this mind bending concepts when you found it for the first time, like functions as arguments and return values of other functions.
If you use very basic Lisp and lambda calculus you don't even need numbers and + operators in base language. You can create numbers from functions and plus and minus functions using same trick and assign them to symbols + and - (see Church encoding)
Why does Lisp allow rebinding of math operators?
for consistency and
because it can be useful.
Doesn't this cause confusion?
No.
Most programming languages, following traditional algebraic notation, have special syntax for the elementary arithmetic functions of addition and subtraction and so on. Rules of priority and association make some function calls implicit. This syntax makes the expressions easier to read at the price of consistency.
LISPs tip the see-saw the other way, preferring consistency over legibility.
Consistency
In Clojure (the Lisp I know), the math operators (+, -, *, ... ) are nothing special.
Their names are just ordinary symbols.
They are core functions like any others.
So of course you can replace them.
Usefulness
Why would you want to override the core arithmetic operators? For example, the units2 library redefines them to accept dimensioned quantities as well as plain numbers.
Clojure algebra is harder to read.
All operators are prefix.
All operator applications are explicit - no priorities.
If you are determined to have infix operators with priorities, you can do it. Incanter does so: here are some examples and here is the source code.

emulating Clojure-style callable objects in Common Lisp

In Clojure, hash-maps and vectors implement invoke, so that they can be used as functions, for example
(let [dict {:species "Ursus horribilis"
:ornery :true
:diet "You"}]
(dict :diet))
lein> "You"
or, for vectors,
(let [v [42 613 28]]
(v 1))
lein> 613
One can make callable objects in Clojure by having them implement IFn. I'm new-ish to Common Lisp -- are callable objects possible and if so what would implementing that involve? I'd really like to be able to do things like
(let ((A (make-array (list n n) ...)))
(loop for i from 0 to n
for j from 0 to m
do (setf (A i j) (something i j)))
A)
rather than have code littered with aref. Likewise, it would be cool if you could access entries of other data structures, e.g. dictionaries, the same way.
I've looked at the wiki entry on function objects in Lisp/Scheme and it seems as if having a separate function namespace will complicate matters for CL, whereas in Scheme you can just do this with closures.
Example of callable objects in a precursor of Common Lisp
Callable objects have been provided before. For example in Lisp Machine Lisp:
Command: ("abc" 1) ; doesn't work in Common Lisp
#\b
Bindings in Common Lisp
Common Lisp has separate namespaces of names for functions and values. So (array 10 1 20) would only make sense, when array would be a symbol denoting a function in the function namespace. Thus the function value then would be a callable array.
Making values bound to variables act as functions mostly defeats the purpose of the different namespaces for functions and values.
(let ((v #(1 2 3)))
(v 10)) ; doesn't work in Common Lisp
Above makes no sense in a language with different namespaces for functions and values.
FLET is used for functions instead of LET.
(flet ((v #(1 2 3 4 5 6 7))) ; doesn't work in Common Lisp
(v 4))
This would then mean we would put data into the function namespace. Do we want that? Not really.
Literal data as functions in function calls.
One could also think of at least allowing literal data act as functions in direct function calls:
(#(1 2 3 4 5 6 7) 4) ; doesn't work in Common Lisp
instead of
(aref #(1 2 3 4 5 6 7) 4)
Common Lisp does not allow that in any trivial or relatively simple way.
Side remark:
One can implement something in the direction of integrating functions and values with CLOS, since CLOS generic functions are also CLOS instances of the class STANDARD-GENERIC-FUNCTION and it's possible to have and use user-defined subclasses of that. But that's usually not exploited.
Recommendation
So, best to adjust to a different language style and use CL as it is. In this case Common Lisp is not flexible enough to easily incorporate such a feature. It is general CL style to not omit symbols for minor code optimizations. The danger is obfuscation and write-only code, because a lot of information is not directly in the source code, then.
Although there may not be a way to do exactly what you want to do, there are some ways to hack together something similar. One option is define a new binding form, with-callable, that allows us to bind functions locally to callable objects. For example we could make
(with-callable ((x (make-array ...)))
(x ...))
be roughly equivalent to
(let ((x (make-array ...)))
(aref x ...))
Here is a possible definition for with-callable:
(defmacro with-callable (bindings &body body)
"For each binding that contains a name and an expression, bind the
name to a local function which will be a callable form of the
value of the expression."
(let ((gensyms (loop for b in bindings collect (gensym))))
`(let ,(loop for (var val) in bindings
for g in gensyms
collect `(,g (make-callable ,val)))
(flet ,(loop for (var val) in bindings
for g in gensyms
collect `(,var (&rest args) (apply ,g args)))
,#body))))
All that's left is to define different methods for make-callable that return closures for accessing into the objects. For example here is a method that would define it for arrays:
(defmethod make-callable ((obj array))
"Make an array callable."
(lambda (&rest indices)
(apply #'aref obj indices)))
Since this syntax is kind of ugly we can use a macro to make it prettier.
(defmacro defcallable (type args &body body)
"Define how a callable form of TYPE should get access into it."
`(defmethod make-callable ((,(car args) ,type))
,(format nil "Make a ~A callable." type)
(lambda ,(cdr args) ,#body)))
Now to make arrays callable we would use:
(defcallable array (obj &rest indicies)
(apply #'aref obj indicies))
Much better. We now have a form, with-callable, which will define local functions that allow us to access into objects, and a macro, defcallable, that allows us to define how to make callable versions of other types. One flaw with this strategy is that we have to explicitly use with-callable every time we want to make an object callable.
Another option that is similar to callable objects is Arc's structure accessing ssyntax. Basically x.5 accesses the element at index five in x. I was able to implement this in Common Lisp. You can see the code I wrote for it here, and here. I also have tests for it so you can see what using it looks like here.
How my implementation works is I wrote a macro w/ssyntax which looks at all of the symbols in the body and defines macros and symbol-macros for some of them. For example the symbol-macro for x.5 would be (get x 5), where get is a generic function I defined that accesses into structures. The flaw with this is I always have to use w/ssyntax anywhere I want to use ssyntax. Fortunately I am able to hide it away inside a macro def which acts like defun.
I agree with Rainer Joswig's advice: It would be better to become comfortable with Common Lisp's way of doing things--just as it's better for a Common Lisp programmer to become comfortable with Clojure's way of doing things, when switching to Clojure. However, it is possible to do part of what you want, as malisper's sophisticated answer shows. Here is the start of a simpler strategy:
(defun make-array-fn (a)
"Return a function that, when passed an integer i, will
return the element of array a at index i."
(lambda (i) (aref a i)))
(setf (symbol-function 'foo) (make-array-fn #(4 5 6)))
(foo 0) ; => 4
(foo 1) ; => 5
(foo 2) ; => 6
symbol-function accesses the function cell of the symbol foo, and setf puts the function object created by make-array-fn into it. Since this function is then in the function cell, foo can be used in the function position of a list. If you wanted, you could wrap up the whole operation into a macro, e.g. like this:
(defmacro def-array-fn (sym a)
"Define sym as a function that is the result of (make-array-fn a)."
`(setf (symbol-function ',sym)
(make-array-fn ,a)))
(def-array-fn bar #(10 20 30 40))
(bar 0) ; => 10
(bar 1) ; => 20
(bar 3) ; => 40
Of course, an "array" defined this way no longer looks like an array. I suppose you could do something fancy with CL's printing routines. It's also possible to allow setting values of the array as well, but this would probably require a separate symbols.

Simple thread macro implementation

Very new to clojure so might be a noob question but here it is. So I read that the -> macro will invoke functions in sequence and I understand how this works.
(-> (+ 1 2) (* 10)) which results in 30
But why does this not do the same?
(defn testing-> [a b]
(list a b)
first)
This returns a function first and not "a" when called as (testing-> "a" "b"). What am I missing here? Using it in the wrong way?
the -> needs to be in the body of the function. it's not magic attributed to functions ending with -> but literally a macro whose name is -> which takes a sequence of things to do and produces a new expression with the same things nested each inside the next:
(defn testing [a b]
(-> [a b]
list
first))
in this exampel, when the -> macro runs it produces a new expression which looks like:
(defn testing [a b]
(first (list [a b])))
For another example, when you call -> with the arguemnts (+ 1 2) (* 10) it returns the expression (* (+ 1 2) 30) which is then evaluated as normal Clojure code.
PS: a macro is a function which takes a Clojure expression and produces another Clojure expression. These run In the middle of the compilation cycle and you can see what they are doing with the macroexpand-1 function.
A macro is something that restructures its input before it gets compiled.
user> (macroexpand '(-> (+ 1 2) (* 10)))
(* (+ 1 2) 10)
testing-> is a function, not a macro, so it does not restructure the input. You would need to rearrange the input forms before evaluation to get a behavior similar to ->. Every valid form needs to be translated into the standard clojure syntax at compile time, which is done via reader-expansion and macro-expansion.
Macro construction uses standard Clojure functions, but the semantics are somewhat unique (a macro should return the form that will be used at runtime). You can use the clojure.repl/source macro to see how various macros are implemented.
Any operations you need can be expressed as functions, and general creating macros should be avoided unless you need a new syntax.

Is there a possibility of multiple statements inside a conditional statement's body?

I'm primarily a C++ (thus an OO/imperative) programmer and I find it quite bizarre that you can only have one statement per evaluation in a conditional statement such as an if-statement in Scheme, a functional language.
For example:
(let ((arg1 0) (arg2 1))
(if (> arg1 arg2)
arg1
arg2)))
Erroneous example:
(let ((arg1 0) (arg2 1))
(if (> arg1 arg2)
(arg1 (display "cool"))
(arg2 (display "not cool"))))
gives me an error of a type "procedure application: expected procedure, given: 2; arguments were: #void"
That can be solved by placing that said conditional statement into different statements within a body of a defined function for example, with the conditional statement's body having separate statements every time as follows:
(if (condition) statement1a statement2a)
(if (condition) statement1b statement2b)
and so on...
It goes without saying that it's not too practical. Not to mention the duplicated code overhead.
Am I missing anything here or is there really no other way?
(let((arg1 0)(arg2 1))
(if (> arg1 arg2)
(begin
(display arg1)
(newline)
(display "cool"))
(begin
(display arg2)
(newline)
(display "not cool"))))
when you say (arg1 (disply "cool")) you are implying that arg1 should be a proceure.
One thing you may be missing is that in Scheme there is no such thing as a "statement". Everything is an expression and things you might consider statements also return a value. This applies to if, which is typically used to return a value (e.g., (if (tea-drinker?) 'tea 'coffee). Unlike C++, most uses of conditionals are not going to be for mutating a variable or printing values. This reduces the need for having multiple expressions in an if clause.
However, as Ross and Rajesh have pointed out, you can use cond (recommended) or use begins in your if clauses. Note that if you have many side effecting computations in a conditional, you might not be using Scheme idiomatically.
#RajeshBhat gave a good example of using begin with an if statement.
another solution is the cond form
(let ([arg1 0] [arg2 1])
(cond
[(< arg1 0) (display "negative!")]
[(> arg1 arg2) (display arg1) (newline) (display "cool")]
[else (display arg2) (newline) (display "not cool")]))
Each line in the cond form has an implicit begin which you can actually see if you look at the implementation of the cond.
(link is to the Chez Scheme documentation, might (read: probably) not be same implementation you are using as it is proprietary, though Petite Chez is free (no compiler in petite version))
http://scheme.com/tspl4/syntax.html#./syntax:s39
Edit: Important note about begin forms and therefore all expressions that have implicit begin's.
the following code
(+ 2 (begin 3 4 5))
evaluates to 7. This is because the return value of a begin form is its last expression. This is just something to keep in mind when using begins. However, using side-effects and things like displays will work just fine in the positions where the 3 and 4 are.
Since you are already using an iterative process in the "inner" procedure, why not use this definition using named let
(define (fact n)
(let inner ((counter 1) (result 1))
(if (> counter n)
result
(inner (+ counter 1) (* result counter)))))
Since the state of the process can be determined with just 2 variables, it will not use that much memory.
for example (fact 6) is computed like this
(inner 1 1)
(inner 2 1)
(inner 3 2)
(inner 4 6)
(inner 5 24)
(inner 6 120)
(inner 7 720)
720
Here is the letrec version of the same procedure:
(define (fact n)
(letrec ((inner
(lambda (counter result)
(if (> counter n)
result
(inner (+ counter 1) (* result counter))))))
(inner 1 1)))
If you feel restricted by Scheme's syntax, you can always change the syntax by defining a macro. A macro is like a lambda, except it generates code at compile-time (like a C++ template) and its arguments don't get evaluated before the macro is invoked.
You can easily make a macro to let you use the syntax that normally means procedure-application, like (arg1 "cool"), to mean "display everything inside the parentheses with a newline after each item". (It'll mean that only inside the macro, of course.) Like this:
(define-syntax print-if
(syntax-rules ()
[(_ c (true-print ...) (false-print ...))
(if c
(display-with-newlines true-print ...)
(display-with-newlines false-print ...))]))
(define-syntax display-with-newlines
(syntax-rules ()
[(_ e)
(begin (display e) (newline))]
[(_ e0 e* ...)
(begin (display-with-newlines e0) (display-with-newlines e* ...)) ]))
(let ([arg1 0] [arg2 1])
(print-if (> arg1 arg2)
(arg1 "cool")
(arg2 "not cool")))
Output:
1
not cool
Don't worry if you don't understand how the macro definitions work right now. If you're just trying out Scheme after mastering C++, no doubt you're experiencing a lot of frustration. You should have a wee glimpse of the kind of power and flexibility Scheme really has.
A big difference between Scheme macros and C++ templates is that in a macro, the entire Scheme language is available to you. A macro tells, using Scheme, how to transform an s-expr into Scheme code, in any completely arbitrary way that you like. The compiler then compiles the Scheme code output by the macro. Since Scheme programs are themselves s-exprs, there are essentially no restrictions (other than lexical scoping and needing to enclose everything in parentheses).
And don't let anyone discourage you from using side-effects if you want to. The glory of Scheme is that you can do whatever you want.