(Scheme) Is it possible to return one of two values depending on input, using only define or math statements? - scheme

The user inputs a number. When the number is above a specified amount, something happens. Something else happens if the number is below the specified amount, instead. Is it possible to achieve this without using any booleans/conditionals/ifs? As in purely through mathematical operations or function definitions?

You can do that with sgn and a hash table, for example (in Racket):
(define trigger-value 42) ; this is the reference value
(define action ; defines the actions that should happen
(hash
-1 (lambda () (displayln "below"))
0 (lambda () (displayln "BINGO"))
+1 (lambda () (displayln "above"))))
(define (test n) ; calls the right action procedure depending on n
((hash-ref action (sgn (- n trigger-value)))))
The expression (- n trigger-value) is negative when n < trigger-value, positive when n > trigger- value, and 0 if they are the same. Applying sgn to that value yields in -1, 0 or 1, respectively. That value is then used to look in the hash table which procedure should be called.
Here, the procedures just display a line, but they could also return a value, for example, which could then be used for further calculations.
testing
> (test 11)
below
> (test 90)
above
> (test 42)
BINGO
EDIT
This is the solution mentioned by #Chris in the comments:
(define action
(list
(lambda () (displayln "below"))
(lambda () (displayln "BINGO"))
(lambda () (displayln "above"))))
(define (test n) ; calls the right action procedure depending on n
((list-ref action (add1 (sgn (- n trigger-value))))))
and this is based on alists:
(define action
(list
(list -1 (lambda () (displayln "below")))
(list 0 (lambda () (displayln "BINGO")))
(list +1 (lambda () (displayln "above")))))
(define (test n) ; calls the right action procedure depending on n
((second (assv (sgn (- n trigger-value)) action))))

Related

How to generate a list of lambdas in scheme?

I am trying to make a procedure which takes a list of lambdas, and uses the return value of these lambdas. In order to create and populate this list, I made the procedure:
(define generate-list-of-numbers-lambdas
(lambda (function)
(if (= (function) 3)
(list (lambda () 2))
(cons (lambda () (- (function) 1))
(generate-list-of-numbers (lambda () (- (function) 1)))))))
This procedure takes a procedure as an argument, and generates a list of numbers from the return value of the argument procedure until 2 (IE the original argument is a procedure which returns 20, the generate-list-of-numbers makes a list (19 18 17... 3 2)
This procedure takes a procedure as an argument (the argument procedure has no arguments, itself, and just returns an integer), however, this generate-list-of-numbers-lambdas procedures generates a list, but only the first element is a lambda.
Your procedure works just fine if you recur using generate-list-of-numbers-lambdas instead of generate-list-of-numbers; you simply forgot the -lambas part of the name.
A couple more things though. Your procedure calls (function) 3 times in the body. If the result needs to be used in more than one place, you should use a let binding.
(define generate-list-of-numbers
(lambda (function)
(let ((x (function))) ;; bind `x` to `(function)`
(if (= x 3) ;; use x
(list (lambda () 2))
(cons (lambda () (- x 1)) ;; use x
(generate-list-of-numbers (lambda () (- x 1)))))))) ;; use x
Next we see (lambda () ...) littered all about the code. A tiny dose of data abstraction goes a long way here -
(define num
(lambda (x)
(lambda () x)))
(define generate-list-of-numbers
(lambda (function)
(let ((x (function)))
(if (= x 3)
(list (num 2)) ;; use num
(cons (num (- x 1)) ;; use num
(generate-list-of-numbers (num (- x 1)))))))) ;; use num
;; calling our procedure is nicer too
(generate-list-of-numbers (num 20))
We see (num (- x 1)) twice again. It should be a let binding.
(define generate-list-of-numbers
(lambda (function)
(let ((x (function)))
(if (= x 3)
(list (num 2))
(let ((next (num (- x 1)))) ;; bind `next`
(cons next (generate-list-of-numbers next)))))) ;; use `next` twice
We used num to put numbers into our container. We will use val to take numbers out.
(define val
(lambda (n)
(n)))
(map val (generate-list-of-numbers (num 20)))
;; '(19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2)
Going back, we see we can use val in our procedure too. Lastly, we rename function to n. This allows us to think purely in terms of our numbers and forget that the values are wrapped a function (thunk), or some other data container.
(define generate-list-of-numbers
(lambda (n) ;; `function` renamed to `n`
(let ((x (val n))) ;; use `val` to read value of `n`
(if (= x 3)
(list (num 2))
(let ((next (num (- x 1))))
(cons next (generate-list-of-numbers next)))))))
(map val (generate-list-of-numbers (num 20)))
;; '(19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2)
All of that said, this is a weird procedure. I can only guess it is a homework assignment or something. It almost seems like you're trying to implement a lazy list of numbers, but it's not quite right. Starting the list at n - 1 and ending at 2 is another obscure choice and red flag. If you can provide a broader goal, I may be able to update the answer and provide additional help.

Scheme - How do I return a function?

This function is displaying the correct thing, but how do I make the output of this function another function?
;;generate an Caesar Cipher single word encoders
;;INPUT:a number "n"
;;OUTPUT:a function, whose input=a word, output=encoded word
(define encode-n
(lambda (n);;"n" is the distance, eg. n=3: a->d,b->e,...z->c
(lambda (w);;"w" is the word to be encoded
(if (not (equal? (car w) '()))
(display (vtc (modulo (+ (ctv (car w)) n) 26)) ))
(if (not (equal? (cdr w) '()))
((encode-n n)(cdr w)) )
)))
You're already returning a function as output:
(define encode-n
(lambda (n)
(lambda (w) ; <- here, you're returning a function!
(if (not (equal? (car w) '()))
(display (vtc (modulo (+ (ctv (car w)) n) 26))))
(if (not (equal? (cdr w) '()))
((encode-n n)(cdr w))))))
Perhaps a simpler example will make things clearer. Let's define a procedure called adder that returns a function that adds a number n to whatever argument x is passed:
(define adder
(lambda (n)
(lambda (x)
(+ n x))))
The function adder receives a single parameter called n and returns a new lambda (an anonymous function), for example:
(define add-10 (adder 10))
In the above code we created a function called add-10 that, using adder, returns a new function which I named add-10, which in turn will add 10 to its parameter:
(add-10 32)
=> 42
We can obtain the same result without explicitly naming the returned function:
((adder 10) 32)
=> 42
There are other equivalent ways to write adder, maybe this syntax will be easier to understand:
(define (adder n)
(lambda (x)
(+ n x)))
Some interpreters allow an even shorter syntax that does exactly the same thing:
(define ((adder n) x)
(+ n x))
I just demonstrated examples of currying and partial application - two related but different concepts, make sure you understand them and don't let the syntax confound you.

Passing a list as a Parameter in Scheme

I am a beginner to functional programming and I want to be able to read values from a console into a list, pass that list as a parameter, and then return the sum of the list in Scheme.
I want to get this result: (display (sum-list-members '(1 2 3 4 5))) but the user must enter these values at the console.
This is what I am working on:
(begin
(define count 0)
(define sum-list-members
(lambda (lst)
(if (null? lst)
0
(+ (car lst) (sum-list-members (cdr lst))))))
(display "Enter a integer [press -1 to quit]: ")
(newline)
(let loop ((i 0))
(define n(read))
(sum-list-members (list n))
(set! count i)
(if (not(= n -1))
(loop (+ i 1)))
)
(newline)
)
Using chicken-scheme, I'd do it like this:
(define (read-number-list)
(map string->number (string-tokenize (read-line))))
Define your sum-list-members as such:
(define (sum-list-members lst)
(fold + 0 lst))
To get string-tokenize to work, you might have to use a certain srfi. Fold is pretty much the same thing as you wrote, except that it's a function that takes a function and initial value as parameters.
The function has to receive 2 parameters, the first parameter is the current value and the second parameter is the value returned by the previous call or the initial value.
(do ((mlist () (cons n mlist))(n (read)(read)))
((= n -1) (display (apply + mlist))))

lambda functions and memory in scheme

I don't understand why if I write
(define (iter-list lst)
(let ((cur lst))
(lambda ()
(if (null? cur)
'<<end>>
(let ((v (car cur)))
(set! cur (cdr cur))
v)))))
(define il2 (iter-list '(1 2)))
and call (il2) 2 times I have printed: 1 then 2
(that's the result I want to have)
But if I don't put (lambda () and apply (il2) 2times I obtain then 1
In other words why associating the if part to a function lambda() makes it keep the memory of what we did when we applied the function before?
This is what's happening. First, it's important that you understand that when you write this:
(define (iter-list lst)
(let ((cur lst))
(lambda ()
...)))
It gets transformed to this equivalent form:
(define iter-list
(lambda (lst)
(let ((cur lst))
(lambda ()
...))))
So you see, another lambda was there in the first place. Now, the outermost lambda will define a local variable, cur which will "remember" the value of the list and then will return the innermost lambda as a result, and the innermost lambda "captures", "encloses" the cur variable defined above inside a closure. In other words: iter-list is a function that returns a function as a result, but before doing so it will "remember" the cur value. That's why you call it like this:
(define il2 (iter-list '(1 2))) ; iter-list returns a function
(il2) ; here we're calling the returned function
Compare it with what happens here:
(define (iter-list lst)
(let ((cur lst))
...))
The above is equivalent to this:
(define iter-list
(lambda (lst)
(let ((cur lst))
...)))
In the above, iter-list is just a function, that will return a value when called (not another function, like before!), this function doesn't "remember" anything and returns at once after being called. To summarize: the first example creates a closure and remembers values because it's returning a function, whereas the second example just returns a number, and gets called like this:
(define il2 (iter-list '(1 2))) ; iter-list returns a number
(il2) ; this won't work: il2 is just a number!
il2 ; this works, and returns 1
When you wrap the if in a lambda (and return it like that), the cur let (which is in scope for the if) is attached to the lambda. This is called a closure.
Now, if you read a little bit about closures, you'll see that they can be used to hold onto state (just like you do here). This can be very useful for creating ever incrementing counters, or object systems (a closure can be used as a kind of inside out object).
Note that in your original code, you renamed lst as cur. You didn't actually need to do that. The inner lambda (the closure to be) could have directly captured the lst argument. Thus, this would produce the same result:
(define (iter-list lst)
(lambda ()
...)) ; your code, replace 'cur' with 'lst'
Here are some example of other closure-producing functions that capture a variable:
(define (always n)
(lambda () n))
(define (n-adder n)
(lambda (m) (+ n m)))
(define (count-from n)
(lambda ()
(let ((result n))
(set! n (+ n 1))
result)))

build-list (error - expects a procedure) Racket/Scheme

Trying to make a function that produces a n by n board
(new-board 2)
is supposed to produce
(list (make-posn 0 0) (make-posn 0 1) (make-posn 1 0) (make-posn 1 1))
The current rendition of my code is as follows:
(define (new-board y)
(build-list y (lambda (x) (build-list x (make-posn y x))))
)
I was pretty certain that it would work, but given my current knowledge and experience in Racket, I couldn't find the error.
I typed in:
> (new-board 3)
and got the error:
build-list: expects a procedure (arity 1); given (make-posn 3 0)
Am I committing a heinous crime by invoking build list inside of a build-list?
Please let me know. Thanks!
About this procedure:
(define (new-board y)
(build-list y (lambda (x) (build-list x
(make-posn y x))))) ;error!
Let's see what build-list receives as parameters. The first parameter is y, a number and the second parameter is a procedure, but you're passing the result of evaluating make-posn, which is not a procedure, it's a value. And that's the reason for the error you're getting.
EDIT 1 :
Now I understand what you intended. I can think of a solution, but it's a bit more elaborated than what you had in mind:
(define (new-board n)
(flatten
(map (lambda (x)
(map (lambda (y)
(make-posn x y))
(build-list n identity)))
(build-list n identity))))
(define (flatten lst)
(if (not (list? lst))
(list lst)
(apply append (map flatten lst))))
Here's how it works:
build-list is just being used for generating numbers from 0 to n-1, and I'm passing identity as the procedure, because no further processing is required for each number
For each number in the list, we also want to generate another list, again from 0 to n-1 because all the coordinates in the board are required. For example if n is 3 the coordinates are '((0 0) (0 1) (0 2) (1 0) (1 1) (1 2) (2 0) (2 1) (2 2))
I'm using a map inside a map for building the nested lists, a technique borrowed from here (see: "nested mappings")
Finally, I had to flatten the generated lists, and that's what flatten does (otherwise, we'd have ended with a list of lists of lists)
EDIT 2 :
Come to think of it, I found an even simpler way, closer to what you had in mind. Notice that the flatten procedure is unavoidable:
(define (new-board n)
(flatten
(build-list n
(lambda (x)
(build-list n
(lambda (y)
(make-posn x y)))))))
Now, when you type this:
(new-board 2)
The result is as expected:
(#(struct:posn 0 0) #(struct:posn 0 1) #(struct:posn 1 0) #(struct:posn 1 1))
If you look up the signature (contract) of build-list1, you see that it is
build-list : Nat (Nat -> X) -> (listof X)
So it takes a (natural) number, and then a function that expects a natural number and gives back an element of the type (X) that you want included in the list. So in your case, what specific type do you want X to be for each call you're making to build-list (it can be different in each case). In the case of the inner build-list, it looks like you're trying to make a list of posns. However, (make-posn y x) immediately makes a single posn and is not a function as build-list expects. So just as you provide a function (lambda (x) ...) to the outer build-list, you should also provide a function (lambda (...) ...) to the inner function.
Choosing the name x for the parameter of the first lambda might be a little confusing. What I might do is change the name of the new-board function's parameter to N, in that it seems like you want to create a board of N rows (and columns). And the purpose of the first build-list is to create each of those rows (or columns, depending how you want to think of it). So if you had:
(define (new-board N)
(build-list N (lambda (x) ...)))
And then you use it like:
(new-board 5)
it will reduce/simplify/evaluate as follows:
==> (build-list 5 (lambda (x) ...))
==> (list ( (lambda (x) (build-list ... x ...)) 0 )
( (lambda (x) (build-list ... x ...)) 1 )
( (lambda (x) (build-list ... x ...)) 2 )
( (lambda (x) (build-list ... x ...)) 3 )
( (lambda (x) (build-list ... x ...)) 4 )
==> (list (build-list ... 0 ...)
(build-list ... 1 ...)
(build-list ... 2 ...)
(build-list ... 3 ...)
(build-list ... 4 ...))
So, there's nothing wrong with nesting build-list. See if you can figure out now how to have the inner build-list work on producing a list of posns once the current row is fixed to a particular x value.
By the way, if you're allowed to use full Racket, there's a nice way to express the computation with for loops:
(define (new-board n)
(for*/list ([i n]
[j n])
(make-posn i j)))
Another way to get the same result but with a different approach is to use an arithmetic trick with quotient and remainder.
(define (new-board n)
(build-list (* n n)
(lambda (k)
(make-posn (quotient k n)
(remainder k n)))))

Resources