I'm confused about destructive operations in Scheme. Let's say I have a list and some destructive procedures defined in the global environment:
(define a '(a b c))
(define (mutate-obj x)
(set! x '(mutated)))
(define (mutate-car! x)
(set-car! x 'mutated))
(define (mutate-cdr! x)
(set-cdr! x 'mutated))
Then we have the following expression evaulation:
(mutate-obj! a) a => (a b c)
(mutate-car! a) a => (mutated b c)
(mutate-cdr! a) a => (mutated . mutated)
Why isn't set! having an effect on a outside its procedure when both set-car! and set-cdr! have? Why isn't the expression on the first line evaluating to (mutated)? How does all of this really work?
The first example isn't working as you imagined. Although both the x parameter and the a global variable are pointing to the same list, when you execute (set! x '(mutated)) you simply set x (a parameter local to the procedure) to point to a different list, and a remains unchanged. It'd be different if you wrote this:
(define (mutate-obj)
(set! a '(mutated)))
Now a gets mutated inside the procedure. The second and third procedures are modifying the contents of the a list, also pointed by x, so the change gets reflected "outside" once the procedure returns.
Related
So from my personal research, it seems that closures / currying seem to be more or less the exact same thing, which can't be obviously correct. So where is the difference?
So here is an example of a closure in Racket:
(define (make-an-adder x)
(lambda (y)
(+ y x)))
(define add3 (make-an-adder 3))
(add3 5)
will give back
8
So where is the difference to currying? Because if i look up documentations and other examples, it seems that they do the exact same thing as i showed for the closure?
Thanks in advance everyone!
So they are different concepts, but both are related to nested lambdas.
A Closure can be created by a lambda that refers to a variable defined outside itself, and is most important when the lambda escapes from the context where that outside variable is defined. The Closure's job is to make sure that variable is preserved when the lambda escapes that context.
A Curried function is a function that can take its arguments in multiple steps, or multiple different function-applications. This normally means there are lambdas nested within lambdas.
Curried functions aren't always closures, though they often are
Most useful curried functions need to use closures, but if the inner lambdas ignore the outer arguments, they aren't closures. A simple example:
(define (curried-ignore-first ignored)
(lambda (y) y))
This is not a closure because the inner lambda (lambda (y) y) is already closed: it doesn't refer to any variables outside itself.
A curried function doesn't always need to ignore the outer arguments... it just needs to be done processing them before it returns the inner lambda, so that the inner lambda doesn't refer to the outer argument. A simple example of this is a curried choose function. The "normal" definition of choose does indeed use a closure:
(define (choose b)
(lambda (x y)
(if b x y))) ; inner lambda refers to `b`, so it needs a closure
However, if the if b is put outside the outer lambda, we can avoid making closures:
(define (choose b)
(if b
(lambda (x y) x) ; not closures, just nested lambdas
(lambda (x y) y)))
Closures aren't always from curried functions
A closure is needed when a inner lambda refers to a variable in an outer context and might escape that context. That outer context is often a function or a lambda, but it doesn't have to be. It can be a let:
(define closure-with-let
(let ([outer "outer"])
(lambda (ignored) outer))) ; closure because it refers to `outer`
This is a closure, but not an example of currying.
Turning a Curried-function-producing-a-closure into one without a closure
The example in the original question is a curried function that produces a closure
(define (make-an-adder x)
(lambda (y)
(+ y x)))
If you wanted to make a version that's still a curried function with the same behavior, but without needing a closure over x in some special cases, you can branch on those before the lambda:
(define (make-an-adder x)
(match x
[0 identity]
[1 add1]
[-1 sub1]
[2 (lambda (y) (+ y 2))]
[3 (lambda (y) (+ y 3))]
[_ (lambda (y) (+ y x))]))
This avoids producing a closure for the cases of x being an exact integer -1 through 3, but still produces a closure in all other cases of x. If you restricted the domain of x to a finite set, you could turn it into a function that didn't need closures, just by enumerating all the cases.
If you don't want a closure over x, but you're fine with a closure over other things, you can use recursion and composition to construct an output function that doesn't close over x:
(define (make-an-adder x)
(cond [(zero? x) identity]
[(positive-integer? x)
(compose add1 (make-an-adder (sub1 x)))]
[(negative-integer? x)
(compose sub1 (make-an-adder (add1 x)))]))
Note that this still produces closures (since compose creates closures over its arguments), but the function it produces does not close over x. Once this version of make-an-adder produces its result, it's "done" processing x and doesn't need to close over it anymore.
I am using the DrRacket environment to try out the Scheme language.
I defined sum+1 as follows:
(define sum+1 '(+ x y 1))
I was wondering why the following expression does not evaluate:
(let ([x 1] [y 2]) (eval sum+1))
whereas doing this returns the correct value:
(define x 1)
(define y 2)
(eval sum+1)
eval does not work with lexical variables at all unless the lexical variable was created in the same expression:
#!r7rs
(import (scheme base)
(scheme eval))
(define env (environment '(scheme base)))
(let ((x 10))
(eval 'x env)) ; ERROR! `x` is not defined
You can think of it as eval always happening top level with the global bindings of the environment you pass to the second argument. You can perhaps trick it by passing values from your lexical environment like this:
(eval '(let ((x 10))
x)
env) ; ==> 10
(let ((x 10))
(eval `(let ((x ,x))
x)
env) ; ==> 10
By the time most Scheme implementations run code local variables are usually stack allocated. Thus something imagine this code:
(define (test v)
(display v)
(newline)
(eval 'v))
Might turn into this at runtime:
(define (test 1 #f) ; indicates 1 argument, no rest
(display (ref 0)) ; fetches first argument from stack
(newline)
(eval 'v)) ; but what is v?, certainly not the first argument
Also you can make corner cases. What happens if you mutate?
(define (test v)
(eval '(set! v 10))
v)
The structure to eval might come from user input so it's not obvious that v gets mutated, also many compiling Scheme implementations need to treat variables that mutate differently so it needs to know before the code runs that v needs special treatment, but it is not decidable because the (set! v 10) might come from the database or user input. Thus by not including local bindings you save yourself a lot of trouble and the language gets easier to optimize and compile.
There are lisp languages that can only be interpreted since it allows for passing macros as first class objects. These languages are impossible to reason about at compile time.
The reason that the command with let does not work is that let creates local variables. This means that the variables it creates can NOT be accessed from just anywhere - only from within let's body argument.
In your example, you defined:
(define sum+1 '(+ x y 1))
Then you commanded this:
(let ([x 1] [y 2]) (eval sum+1))
This doesn't work because x and y are only being defined in the eval statement, not within the procedure sum+1. This may seem counter-intuitive, but it prevents many errors with other inputs.
Your second example was:
(define x 1)
(define y 2)
(eval sum+1)
This does works because x and y are defined globally. This means that they CAN be accessed anywhere, and by anything. They are then applied to the sum+1 definition and are able to be printed. Please respond with any questions or feedback you have!
I am new to Racket and functional languages in general. For now I am just trying to prepend items to a list. The concepts are a bit confusing and not sure why my code isn't working.
I am trying to do dot product calculations.
I have a function called "dProduct" that takes 2 lists (A and B) and multiplies each corresponding element in them.
;function takes dot product
(define (dProduct A B)
(define C '()) ; define list to store the multiplied elements
;multiply ea lists elements
(for ([i A] [j B])
(display (* i j)) ;THIS WORKS
(cons (* i j) C) ;APPARENTLY DOESN'T WORK
)
;THIS FOR LOOP DISPLAYS NOTHING
;display the new list "C"
(for ([k C])
(display k)
)
)
I don't understand why I can't use cons to prepend the new multiplied elements to my new list "C". What am I missing? Everything compiles fine. Would like to figure this out so I can finish this function :) Any help would be great. Thanks!
Lists are immutable, and cons does not prepend an element to an existing list. Instead, it produces a new list with the element prepended:
> (define x '(2 3))
> (cons 1 x)
'(1 2 3)
> x
'(2 3)
Since your question is tagged functional-programming, I will assume that you probably want to know how to do this functionally, and functional programming generally discourages mutating values or bindings.
Instead of mutating a binding, you should build up a new structure functionally. The easiest way to do this is to change your use of for to for/list, which produces a list of return values:
(define C
(for/list ([i A] [j B])
(* i j)))
For this program, you could make it even simpler by using the higher-order function map, which acts like a “zip” when provided more than one list argument:
(define C (map * A B))
Since for always returns #<void>, it’s only useful for producing side-effects, and in functional programming, you generally try and keep side-effects to a minimum. For that reason, you will likely find that for/list and for/fold are actually much more commonly useful in idiomatic Racket than plain for is.
Current C list has to be given new value of (cons (* i j) C) and this can be done using set! :
(define (dProduct A B)
(define C '())
(for ([i A] [j B])
(displayln (* i j))
(set! C (cons (* i j) C))) ; NOTE set! HERE.
(for ([k C])
(displayln k)))
Note that the use of set! is strongly discouraged and for/list is much better way to achieve desired result here.
I'm doing some exercises in Racket, and ran into a problem I couldn't seem to query the docs for.
I want to generate the following curries of modulo for a list of divisors:
(define multlist '[3 5])
(define modfuncs (map (lambda x ;# make some modulos
(curry modulo x)) multlist))
This produces a list of curried procedures, which sounds promising, but when I try to test one of them, I get the following error:
-> (car modfuncs)
#<procedure:curried>
-> ((car modfuncs) 3)
; modulo: contract violation
; expected: integer?
; given: '(3)
; argument position: 1st
; [,bt for context]
Assuming this isn't a terrible way to do this, how do I unquote the values of multlist passed to the curry/map call so these functions will evaluate correctly?
You're actually doing this correctly, albeit with a tiny mistake:
(lambda x (curry modulo x))
This doesn't do what you think it does. What you actually want is this:
(lambda (x) (curry modulo x))
See the difference? In the former, x is not within an arguments list, so it will actually be passed a list of all arguments passed to the function, not a single argument.
You can see this behavior for yourself with the following simple program:
((lambda x x) 1 2 3)
; => '(1 2 3)
Therefore, your curry function is receiving a list of one number for x, not an actual integer.
So perhaps the more satisfying answer is: why does Racket do this? Well, this is actually a result of Racket/Scheme's rest parameter syntax. Inserting a dot before the last argument of a lambda makes that parameter a rest parameter, which becomes a list that holds all additional parameters passed to the function.
((lambda (a b . rest) rest) 1 2 3 4 5)
; => '(3 4 5)
However, this isn't actually just a special syntax. The dot notation actually has to do with how Racket's reader reads lists and pairs in syntax. The above parameter list actually becomes an "improper" list made up of the following cons sequence:
(cons 'a (cons 'b 'rest))
The same function without the rest parameter would have a proper list as its argument declaration, which would look like this instead:
(cons 'a (cons 'b null))
So then, what about the original x just standing alone? Well, that's an improper list with no preceding arguments! Doing ( . rest) wouldn't make any sense—it would be a syntax error—because you'd be trying to create a pair with no car element. The equivalent is just dropping the pair syntax entirely.
My professor has given us a refresher assignment in clisp. One exercise is to achieve the same thing in three ways: Return a flattened list of all positive integers in a given list.
Now, there's only one way I really like doing this, using cons and recursion, but he wants me to do this using mapcan and a loop (I suspect lisp is not his first choice of language because this style of coding feels extremely resistant to the nature of lisp). I'm having a hard time working out how one would do this using a loop...I need to first start a list, I suppose?
I apologize for vague language as I'm not really sure how to TALK about using a functional language to write procedurally. Following is my first attempt.
(defun posint-loop (l)
(loop for i in l
do (if (listp i)
(posint-loop i)
(if (integerp i)
(if (> i 0)
(append i) ; this doesn't work because there's nothing to
; start appending to!
nil)
nil))))
In order to establish a new lexical binding, use let or the with keyword of loop. In order to extend an existing list, you might want to use push; if you need the original order, you can nreverse the new list finally.
Another way would be to use the when and collect keywords of loop.
Another hint: mapcan implicitly creates a new list.
Mapcan applies a function to each element of a list, expecting the function to return a list, and then concatenates those resulting lists together. To apply it to this problem, you just need to process each element of the toplevel list. If the element is a list, then you need to process it recursively. If it's not, then you either need to return an empty list (which will add no elements to the final result) or a list of just that element (which will add just that element to the final result):
(defun flatten2 (list)
(mapcan (lambda (x)
(cond
((listp x) (flatten2 x))
((and (integerp x) (plusp x)) (list x))
(t '())))
list))
(flatten2 '((a 1 -4) (3 5 c) 42 0))
;=> (1 3 5 42)
With loop, you can do just about the same thing with the recognition that (mapcan f list) is functionally equivalent to (loop for x in list nconc (funcall f x)). With that in mind, we have:
(defun flatten3 (list)
(loop for x in list
nconc (cond
((listp x) (flatten3 x))
((and (integerp x) (plusp x)) (list x))
(t '()))))