>-) wrote:somehow, funcall feels kind of crude and inelegant.

Religious war: You are

objectively correct, that is why Lisp-1's (single namespace Lisps) are the best.

>-) wrote:i've been trying church numerals and arithmetic. it worked up until i tried exponentials. [...] can anyone offer some advice?

Yes, write down your types when dealing with complex higher-order functions. In an MLish notation, your Church numerals have type:

'a church2 = (('a -> 'a) * 'a) -> 'a

as opposed to the traditional:

'a church1 = ('a -> 'a) -> 'a -> 'a

With traditional Church numerals, "(unchurch (n m))" works because "int church1" is "(int -> int) -> int -> int", which is the same as "(int -> int) -> (int -> int)", so an "int church1" can be passed to an "(int -> int) church1". Thus, n can take the type "(int -> int) church1" and m can take the type "int church1", and "(n m)" will have the type "(int -> int) -> (int -> int)", which is to say "int church1", which is the desired type to pass to unchurch.

In your case, say we have:

Code: Select all

`(defun cexp (m n)`

(lambda (f x) EXP))

and we want to write a correctly typed EXP along the lines of "(((n m) f) x)". Let's say that f and x have types ('b -> 'b) and 'b, respectively. There's simply no way that we can pass m to n without converting it to a church1. Suppose we do so. Then, the simple "((n (church2->church1 m) f) x)" is properly typed:

(church2->church1 m) gets type ('b church1), i.e. (('b -> 'b) -> 'b -> 'b)

n gets type (('b -> 'b) church2)

This would be your cexp5, IF your "curry" were church2->church1, but it is not. church2->church1 does match the definition of currying in the sense of converting a function from a multiple-argument form to a curried form, but your "curry" is currying in the sense of partial application. In types:

Your curry (where X and Y are potentially multiple arguments):

(X * Y -> z) * X -> (Y -> z)

Conversion curry (of a two-argument function):

(x * y -> z) -> x -> y -> z

That is:

Code: Select all

`(defun curry2 (f)`

(lambda (x)

(lambda (y)

(funcall f x y))))

Takes a two-argument f and returns a curried version, and your cexp5 will work with curry2.

(Note that a more general conversion curry function would be: (curryn n f) with type:

int * (x1 * ... xn -> y) -> x1 -> ... -> xn -> y

but we don't need to write that now.)

A more general piece of advice would be to try to understand more specifically what's going wrong before changing something. I don't get the impression that trying all those versions helped. If you either engaged in a type analysis or perhaps tried to learn your implementation's debugger, it might have helped. But I'm not familiar with GNU CLISP, so I can't give more specific advice in this regard.