Discussion:
compose combinator
(too old to reply)
Gregory Ramirez
2020-02-16 16:15:56 UTC
Permalink
Here is a version of the compose combinator:

(defparameter c
(eval
(let ((f (gensym)) (g (gensym)) (x (gensym)))
`(lambda (,f)
(lambda (,g)
(lambda (,x)
(funcall ,f (funcall ,g ,x)))))))
"Example: (funcall (funcall (funcall c #'1+) #'char-code) #\a) ==> 98")

Is there a way to define c without using eval and avoiding
variable capturing (here by using gensym)?
Alan Bawden
2020-02-16 22:09:53 UTC
Permalink
Post by Gregory Ramirez
(defparameter c
(eval
(let ((f (gensym)) (g (gensym)) (x (gensym)))
`(lambda (,f)
(lambda (,g)
(lambda (,x)
(funcall ,f (funcall ,g ,x)))))))
"Example: (funcall (funcall (funcall c #'1+) #'char-code) #\a) ==> 98")
Is there a way to define c without using eval and avoiding
variable capturing (here by using gensym)?
(defparameter c
(lambda (f)
(lambda (g)
(lambda (x)
(funcall f (funcall g x))))))

Those GENSYMs aren't protecting you against anything. There is no
"variable capturing" to worry about here.
--
Alan Bawden
Gregory Ramirez
2020-02-16 23:25:26 UTC
Permalink
Post by Gregory Ramirez
[...]
(defparameter c
(lambda (f)
(lambda (g)
(lambda (x)
(funcall f (funcall g x))))))
Those GENSYMs aren't protecting you against anything. There is no
"variable capturing" to worry about here.
--
Alan Bawden
I get the error "invalid number of arguments: 1" when defining

(defparameter g #'(lambda () 1))

before

(defparameter c
(lambda (f)
(lambda (g)
(lambda (x)
(funcall f (funcall g x))))))

That's why i added this eval-backquote stuff. But perhaps there is an
expression using only one argument lambda and gensym to achieve the
same.
Are there any security problems with using eval in this context?
Alan Bawden
2020-02-17 00:39:06 UTC
Permalink
Post by Gregory Ramirez
Post by Gregory Ramirez
[...]
(defparameter c
(lambda (f)
(lambda (g)
(lambda (x)
(funcall f (funcall g x))))))
Those GENSYMs aren't protecting you against anything. There is no
"variable capturing" to worry about here.
--
Alan Bawden
I get the error "invalid number of arguments: 1" when defining
(defparameter g #'(lambda () 1))
I doubt it. You are programming in Common Lisp, right?
Post by Gregory Ramirez
before
(defparameter c
(lambda (f)
(lambda (g)
(lambda (x)
(funcall f (funcall g x))))))
That's why i added this eval-backquote stuff.
Why? There is no connection. The "eval-backquote stuff" is just a waste
of time. The simple version will result in _exactly_ the same behavior as
your complicated version.
Post by Gregory Ramirez
But perhaps there is an expression using only one argument lambda and
gensym to achieve the same.
We have no idea what your probem really is, but you have clearly horribly
confused yourself somehow. If your problem went away when you added the
eval-backquote stuff, it's because you changed something else at the same
time and didn't notice what you were really doing.
Post by Gregory Ramirez
Are there any security problems with using eval in this context?
I've been writing Lisp programs for 45 years and I may have used EVAL all
of four times. It is never necessary except in truely exceptional
circumstances. An inexperienced programer who thinks he needs to use EVAL
to solve a problem is either mistaken (99% of the time) or he has chosen a
problem that is far above his present capabilities (1% of the time).

If you really want help, you should tell us _exactly_ what you are doing
that didn't work as you expected. Something like: "I'm using SBCL version
9.99.99, and when I entered the following three expressions, I expected
blah, blah, blah to happen, but instead..."
--
Alan Bawden
Alan Bawden
2020-02-17 04:13:58 UTC
Permalink
Post by Gregory Ramirez
Post by Gregory Ramirez
[...]
(defparameter c
(lambda (f)
(lambda (g)
(lambda (x)
(funcall f (funcall g x))))))
Those GENSYMs aren't protecting you against anything. There is no
"variable capturing" to worry about here.
--
Alan Bawden
I get the error "invalid number of arguments: 1" when defining
(defparameter g #'(lambda () 1))
I occurs to me that you are probably shooting yourself in the foot by using
DEFPARAMETER. DEFPARAMETER has the side effect of turning the variable
Post by Gregory Ramirez
(defparameter c
(lambda (f)
(lambda (g)
(lambda (x)
(funcall f (funcall g x))))))
The G in (LAMBDA (G) ...) is being bound dynamically rather than lexically.
That probably screws up other parts of your program that you haven't shown
us.

This is why variables defined using DEFPARAMETER are usually given names
that start and end with "*", as in:

(defparameter *g* #'(lambda () 1))

That way you are less likely to accidentally try to use it as a variable
and hurt yourself.

Simalarly for your global variable named "C". Call it "*C*" instead.
--
Alan Bawden
Ben Bacarisse
2020-02-17 11:34:04 UTC
Permalink
Post by Gregory Ramirez
(defparameter c
(eval
(let ((f (gensym)) (g (gensym)) (x (gensym)))
`(lambda (,f)
(lambda (,g)
(lambda (,x)
(funcall ,f (funcall ,g ,x)))))))
"Example: (funcall (funcall (funcall c #'1+) #'char-code) #\a) ==> 98")
Is there a way to define c without using eval and avoiding
variable capturing (here by using gensym)?
Why are using a variable or parameter for this? If you can use a
function then you could use the obvious:

(defun c (f g)
(lambda (x) (funcall f (funcall g x))))

(funcall (c #'1+ #'char-code) #\a)

but I notice your example is "Curried". If that is a hard requirement,
you could have

(defun cc (f)
(lambda (g) (lambda (x) (funcall f (funcall g x)))))

(funcall (funcall (cc #'1+) #'char-code) #\a)

If you need the third "funcall" you can refer to cc as #'cc:

(funcall (funcall (funcall #'cc #'1+) #'char-code) #\a)
--
Ben.
Gregory Ramirez
2020-02-17 13:37:13 UTC
Permalink
Post by Ben Bacarisse
[...]
Why are using a variable or parameter for this? If you can use a
(defun c (f g)
(lambda (x) (funcall f (funcall g x))))
(funcall (c #'1+ #'char-code) #\a)
but I notice your example is "Curried". If that is a hard
requirement, you could have
(defun cc (f)
(lambda (g) (lambda (x) (funcall f (funcall g x)))))
(funcall (funcall (cc #'1+) #'char-code) #\a)
(funcall (funcall (funcall #'cc #'1+) #'char-code) #\a)
--
Ben.
Thank you all.
Post by Ben Bacarisse
but I notice your example is "Curried". If that is a hard
requirement, you could have
No hard requirement. Just experimenting with lambda calculus. For
that I wanted the code to look as close as possible to lambda
expressions (and using only unitary functions).

Using mit-scheme:

(define g (lambda () 1))

(define square (lambda (n) (* n n)))

(define 1+ (lambda (n) (+ n 1)))

(define c (lambda (f) (lambda (g) (lambda (x) (f (g
x))))))

(((c 1+) square) 2) ==> 5

As Alan Bawden hinted I was ignorant to the fact that Common Lisp has
dynamic binding.
Ben Bacarisse
2020-02-17 15:32:41 UTC
Permalink
Gregory Ramirez <***@yahoo.com> writes:
<cut>
Post by Gregory Ramirez
(define g (lambda () 1))
(define square (lambda (n) (* n n)))
(define 1+ (lambda (n) (+ n 1)))
(define c (lambda (f) (lambda (g) (lambda (x) (f (g
x))))))
(((c 1+) square) 2) ==> 5
Yes, in Scheme, you don't need funcall (or apply) because the head
position in a form is evaluated and function values are treated just
like any other.

If you want to play with lambda calculus and combinators like compose,
Scheme will give you the cleanest experience.
--
Ben.
Alan Bawden
2020-02-18 01:32:07 UTC
Permalink
Post by Gregory Ramirez
As Alan Bawden hinted I was ignorant to the fact that Common Lisp has
dynamic binding.
Just to be clear, Common Lisp has dynamic binding as an _option_. By
default, variable binding is lexical. You only get dynamic binding if you
ask for it. (And you accidentally asked for it.)

If you are just trying to play around with Lambda Calculus, you will be
much better off sticking to Scheme, where Common Lisp's historical roots
don't get in your way.
--
Alan Bawden
Kaz Kylheku
2020-02-18 02:49:59 UTC
Permalink
Post by Alan Bawden
Post by Gregory Ramirez
As Alan Bawden hinted I was ignorant to the fact that Common Lisp has
dynamic binding.
Just to be clear, Common Lisp has dynamic binding as an _option_. By
default, variable binding is lexical. You only get dynamic binding if you
ask for it. (And you accidentally asked for it.)
Not quite, of course.

For global variables, Common Lisp doesn't have a standard-defined option
for lexical binding.

You can assign to a hitherto unknown variable using setf/setq
instead of using defvar/defparameter.

In some implementations, this gets you a de-facto lexical variable:
the symbol's value cell gets a binding and that's it.

In some implementations, it has the additional effect of setting up the
symbol for dynamic binding, like defvar and defparameter.
Alan Bawden
2020-02-18 18:34:38 UTC
Permalink
Post by Kaz Kylheku
Post by Alan Bawden
Post by Gregory Ramirez
As Alan Bawden hinted I was ignorant to the fact that Common Lisp has
dynamic binding.
Just to be clear, Common Lisp has dynamic binding as an _option_. By
default, variable binding is lexical. You only get dynamic binding if you
ask for it. (And you accidentally asked for it.)
Not quite, of course.
Actually, I think what I said was perfectly correct. But yes, I did not
burden the original poster with the complete sordid history of Common Lisp
and how it got to be the way that it is today. I did start down that path
when composing my reply, but I deleted that text as being unhelpful.
--
Alan Bawden
Loading...