What is the difference between foldr and apply in Scheme? - scheme

Programming language: Scheme/DrRacket
I see no difference in usage between foldr and apply
Can anyone explain how they are different? As far as I can tell you can the same thing with foldr that you can with apply. Thank you!

They're very different, although in some cases they may be equivalent.
(apply func '(1 2 3))
is equivalent to
(func 1 2 3)
(foldr func 0 '(1 2 3))
is equivalent to
(func (func (func 3 0) 2) 1)
In cases where the function is associative and commutative, and it allows you to provide a variable number of arguments, the results will be the same. For example
(apply + '(1 2 3)) == (foldr + 0 '(1 2 3))
But foldr can be used to combine the results of functions that just take two arguments, or use more flexible ways to combine the results.
For more information about foldr, see Map, Filter, Foldr in DrRacket/Scheme

Related

Simplistic way to think of the apply function

In trying to 'reduce' the apply function, is the correct a proper understanding?
For example for (apply func args)
Remove the (apply and matching ).
Inset the func as the first element of the args, moving the outer quote in one level if necessary.
Here would be an application:
; (add-pairs '((1 2)(3 4))) --> (3 7)
(define (add-pairs ps)
(if (null? ps) nil
(cons (+ (car (car ps)) (cadr (car ps))) (add-pairs (cdr ps)))))
(apply add-pairs '(((1 2) (3 4))))
xxxxxxx x
; Remove the "(apply " and matching ")"
add-pairs '(((1 2) (3 4)))
------------^
; Insert the function into the args, moving the quote in one level if required.
(add-pairs '((1 2) (3 4)))
Is the above an accurate way to show how the apply gets added in, or am I missing anything?
The example is unfortunate, as it only leaves one argument after "the opening of the parentheses". But yes, that's how I also think about it. The simpler the better, :) as long as it is correct.
Except that of course the values in the list are first evaluated, so it's not a simply-syntactical process. But as a basic example,
(apply + (list 1 2 3))
==
( + 1 2 3 )
i.e. the parens around the arguments is what goes away.
For a non-trivial example, see
Matrix multiplication in scheme, List of lists
It seems like you know Python. I personally think that apply in Scheme and star operator * in Python are quite similar.
Imagine you want to zip several lists, which were themselves packed inside a list. Trying to call
list_of_lists = [[1, 2],[3, 4]]
zip(list_of_lists)
would not give you [(1, 3), (2, 4)], so you write
zip(*list_of_lists)
# here it's the same as
zip(list_of_lists[0], list_of_lists[1])
using the iterable unpacking operator *. A (pretty full) alternative to this in Racket/Scheme is using an apply function:
(define list-of-lists '((1 2) (3 4)))
(apply zip list-of-lists)
;; here it's the same as
(zip (car list-of-lists) (cadr list-of-lists))
(If, of course, zip in Scheme was defined the same way as in Python, requiring arbitrary number of arguments)
But you can definitely see the difference here, the syntactic one. In Python version of apply we are 'applying' this * to arguments and then pass what was 'returned' to calling function (zip). Scheme acts like a functional language and reverses everything inside out (at least that's how I see it): you're 'applying' apply to a function and its arguments and then it handles everything itself.
The other significant difference is that, of course, apply in Scheme is a normal function, so we can write e.g.
(define (apply-func-to-sum-and-args func args)
(func + args))
(apply-func-to-sum-and-args apply (list 1 2 3))
;; returns 6
Though I believe (correct me if I'm wrong) that this function cannot be written in pure Scheme and it calls some weird C function under the hood.

Any way to map functions with more than one argument in Scheme/Racket?

I'm currently doing an introductory course in Racket/Scheme, and am currently studying map, apply, and fold. For the most part, I've been assuming that map can only work on lambdas that accept a single argument. However, for certain problems I would find it incredibly useful to get around this somewhat - say, having a function that can be mapped to a list whilst also carrying an accumulator that updates independently for each recursive function call. While I can't get much more specific than that for fear of violating Honor Code, is there any way to get around being unable to give each recursive call an accumulator if you plan to use map?
map takes as many lists as you want:
(map + '(1 2 3) '(3 2 1) '(3 3 3)) ; ==> (7 7 7)
fold has an accumulator:
(foldl (lambda (a b c acc) (+ a b c acc)) 1 '(1 2 3) '(3 2 1) '(3 3 3)) ; ==> 22

Alternating Sum Using Foldr/Foldl (Racket)

Back again with another Racket question. New to higher order functions in general, so give me some leeway.
Currently trying to find the alternating sum using the foldr/foldl functions and not recursion.
e.g. (altsum '(1 3 5 7)) should equal 1 - 3 + 5 - 7, which totals to -4.
I've thought about a few possible ways to tackle this problem:
Get the numbers to add in one list and the numbers to subtract in another list and fold them together.
Somehow use the list length to determine whether to subtract or add.
Maybe generate some sort of '(1 -1 1 -1) mask, multiply respectively, then fold add everything.
However, I have no clue where to start with foldl/foldr when every operation is not the same for every item in the list, so I'm having trouble implementing any of my ideas. Additionally, whenever I try to add more than 2 variables in my foldl's anonymous class, I have no idea what variables afterward refer to what variables in the anonymous class either.
Any help or pointers would be greatly appreciated.
We can leverage two higher-order procedures here: foldr for processing the list and build-list for generating a list of alternating operations to perform. Notice that foldr can accept more than one input list, in this case we take a list of numbers and a list of operations and iterate over them element-wise, accumulating the result:
(define (altsum lst)
(foldr (lambda (ele op acc) (op acc ele))
0
lst
(build-list (length lst)
(lambda (i) (if (even? i) + -)))))
It works as expected:
(altsum '(1 3 5 7))
=> -4
Your idea is OK. You can use range to make a list of number 0 to length-1 and use the oddness of each to determine + or -:
(define (alt-sum lst)
(foldl (lambda (index e acc)
(define op (if (even? index) + -))
(op acc e))
0
(range (length lst))
lst))
As an alternative one can use SRFI-1 List Library that has fold that allows different length lists as well as infinite lists and together with circular-list you can have it alterate between + and - for the duration of lst.
(require srfi/1) ; For R6RS you import (srfi :1)
(define (alt-sum lst)
(fold (lambda (op n result)
(op result n))
0
(circular-list + -)
lst))
(alt-sum '(1 3 5 7))
; ==> -4

Scheme skip or continue during lambda map

I am building a function that takes a set of integers, and returns a subset of the odd integers. I am running into the problem that I need to skip over the even integers in my map, but right now my function returns #<void> instead.
(define (oddSubset set)
(map
(lambda (x)
(cond
((odd? x) x)))
s))
In use:
> (oddSubset '(1 2 3))
'(1 #<void> 3)
Is there logic I can use like "else, continue onto next element"?
Note: I am trying to rewrite the built in filter function
map does not have the possibility to skip, but you can use filter instead:
(filter odd? '(1 2 3 4 5 6)) ; ==> (1 3 5)
Or you can use fold-right
(fold-right (lambda (e acc)
(if (odd? e)
(cons e acc)
acc))
'()
'(1 2 3 4 5 6)) ; ==> (1 3 5)
I assume #!r6rs. Both fold-right and filter are in the library (rnrs lists (6)). There is also SRFI-1 which gives both of these procedures for a R5RS language.
In the none standard language #!racket uses the name foldr in place of fold-right.
map looks like a weird choice for this. By definition it maps a function onto each element in a list and returns the list of the results, so trying to "skip" elements seems unnatural.
filter is what you're looking for.
(filter odd? '(1 2 3))
'(1 3)
map applies a function on all elements. Each invocation of the function is supposed to be independant from the others. Even if you introduce a state with a closure, you can't avoid map to build a list of same size as your input.
You want to (re-)implement the filter function. If you want to do it by yourself, you should try to use foldl and foldr instead.
(cond
((odd? x) x))
map check each element in the list: if it is odd, then return that element. But you did not tell your program what to do when the element is not odd, so map return void.
To solve your problem: use filter instead, since map will return something for each element in the list.
If you want to know how to implement filter, try reading the second chapter of SICP

Map, Filter, Foldr in DrRacket/Scheme

Programming language: Scheme/DrRacket
We're currently going over map, filter, and foldr in my comp sci class. I understand that all three can be used to create abstract functions, but I am honestly a little confused about the difference between the three and when I'd use each one.
Anyone care to explain what each is used for and how they are different? Unfortunately my book is not very clear.
The basic idea is that all three are ways of applying some function to all the elements of a list.
Map is perhaps the simplest--you just apply the function to each element of the list. This is basically the same as a for-each loop in other languages:
(map (lambda (x) (+ x 1)) '(1 2 3))
=> (2 3 4)
Basically, map is like this: (map f '(1 2 3)) is the same as (list (f 1) (f 2) (f 3)).
Filter is also simple: the function acts like an arbiter, deciding whether to keep each number. Imagine a really picky eater going through a menu and whining about the things he won't eat ;)
(filter (lambda (x) (equal? x 1)) '(1 2 3))
=> (1)
Fold is the hardest to understand, I think. A more intuitive name would be "accumulate". The idea is that you're "combining" the list as you go along. There are some functions in ever day use that are actually folds--sum is a perfect example.
(foldr + 0 '(1 2 3))
=> 6
You can think of the fold as taking the function and putting it between each element in the list: (foldr + 0 '(1 2 3)) is the same as 1 + 2 + 3 + 0.
Fold is special because, unlike the other two, it usually returns a scalar value--something that was the element of the list rather than the list itself. (This isn't always true, but think of it this way for now anyway.)
Note that I may not have gotten every detail of the code perfect--I've only ever used a different, older implementation of Scheme so I might have missed some Racket details.
I can recommend these finger exercises (and the text that comes before):
http://htdp.org/2003-09-26/Book/curriculum-Z-H-27.html#node_idx_1464

Resources