>-) 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
Code: Select all
(defun curry2 (f)
(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.