How to calculate specific combinations of a list? (Matchmaking) - algorithm

A friend of mine plays on a volleyball league and posed me with an interesting problem:
Each of the following letters represents a pair of players
; player pairs (24)
'(a b c d e f g h i j k l m n o p q r s t u v w x)
Create matches where 3 pairs are grouped to form a team (6 players on a team)
; teams
'((a b c) (d e f) (g h i) (j k l) (m n o) (p q r) (s t u) (v w x))
Combinations of teams will make up a match
; matches
'(((a b c) (d e f))
((g h i) (j k l))
((m n o) (p q r))
((s t u) (v w x)))
In a given night, they may play 8 to 12 matches, but before each match, the pairs of players will randomized. It is the facilitator's intentions to shuffle the teams as much as possible, but often times the result is far from a good distribution. 'a will get paired too many times with 'b etc.
In the scenario where '(a b c) form a team, in an ideal situation 'a would not play on a team with 'b or 'c again. Likewise, 'b would not play again with 'c, if possible.
Simply calculating the combinations for C(24 choose 3), there are 2,024 possible teams...
'((a b c)
(a b d)
(a b e)
...)`
I was thinking I could filter out non fully unique team combinations, but this does not really lead me closer to my solution.
Consider the two following
'(a b c) ; team1
'(a w x) ; team2
These are two fully unique team combinations, but of course we couldn't put them in a match because pair 'a cannot possibly play on two teams simultaneously. So these team combos should never be provided in a single match solution.
Another issue is, the player pairs may not be equally divisible by 6.
; player pairs (26)
'(a b c d e f g h i j k l m n o p q r s t u v w x y z)
; teams
'((a b c) (d e f) (g h i) (j k l) (m n o) (p q r) (s t u) (v w x))
; matches
'(((a b c) (d e f))
((g h i) (j k l))
((m n o) (p q r))
((s t u) (v w x)))
; sit-out this game
'(y z)
Question 1:
How can I generate a list of all possible matches composed of unique team combinations?
Question 2:
How can I expand the algorithm to accommodate the "sit out" players. In the event the list of player pairs is not divisible by 6, each player pair has to play/sit-out in an equal number of matches.
--
So I don't have much code to show for this because I keep hitting dead ends. The furthest I got was getting X choose Y implemented such that I had a list of all possible team combinations. I ran into trouble filtering out non-fully-unique combinations. Even if I were to succeed at that, I wouldn't know how to compose the fully unique combinations into matches.
Answers don't have to include a full implementation but pointing me in the right direction would be a lot of help. I don't have a lot of experience with this kind of computation.

You can build a solution to question 1 using the combinations function and some extra filtering. First some data definitions:
;; A Player-Pair is a Symbol.
;; A Team is a (List Player-Pair Player-Pair Player-Pair).
;; A Match is a (List Team Team) where the teams are disjoint.
;; Player-Pairs : (Listof Player-Pair)
(define player-pairs '(a b c d e f g h i j k l m n o p q r s t u v w x))
So, what we want is to find the matches, but to do that we need to find a set of teams from all the combinations of 3 player-pairs, and then filter that so that it satisfies your constraint that two player-pairs should never be on a team with each other more than once.
I don't know how to do that yet, but it sounds complicated, so make it a helper function called filter-team-combinations.
;; find-teams : (Listof Player-Pair) -> (Listof Team)
(define (find-teams player-pairs)
(filter-team-combinations (combinations player-pairs 3)))
;; filter-team-combinations : (Listof Team) -> (Listof Team)
;; Filters out teams where a player-pair would on a team with another
;; player-pair for the second time.
(define (filter-team-combinations teams) ....)
Hm. To know whether a given Team has two player-pairs that have already been on the team together, I'll need to keep track of that as well. It's probably going to be recursive, and the pairs of player-pairs that have already been together will change from one recursive call to the next. As we add to the result list, the list of pair-pairs will grow larger. So we need to add it as an argument, which starts out as an empty list.
;; find-teams : (Listof Player-Pair) -> (Listof Team)
(define (find-teams player-pairs)
(filter-team-combinations (combinations player-pairs 3) (list)))
;; A Pair-Pair is a (List Player-Pair Player-Pair)
;; filter-team-combinations : (Listof Team) (Listof Pair-Pair) -> (Listof Team)
;; Filters out teams where a player-pair would on a team with another
;; player-pair for the second time.
;; pair-pairs is an accumulator that stores the pair-pairs that we've
;; seen so far.
(define (filter-team-combinations teams pair-pairs) ....)
The filter-team-combinations function processes a list of teams, and a list can be either empty or the first team consed onto the rest of the teams:
(define (filter-team-combinations teams pair-pairs)
(cond [(empty? teams) ....]
[else .... (first teams) .... (rest teams) ....]))
For the base case, if there are no teams to filter, we return the empty list. For the recursive case, well, it will have to look at the pairs of player-pairs that the first team contains, check whether those conflict with the existing pair-pairs, and branch on that:
(define (filter-team-combinations teams pair-pairs)
(cond [(empty? teams) (list)]
[else
(define new-pair-pairs (combinations (first teams) 2))
(cond [(pair-pairs-conflict? new-pair-pairs pair-pairs)
.... (first teams) .... (rest teams) ....]
[else
.... (first teams) .... (rest teams) ....])]))
;; pair-pairs-conflict? : (Listof Pair-Pair) (Listof Pair-Pair) -> Boolean
(define (pair-pairs-conflict? as bs) ....)
So, pretending that pair-pairs-conflict? does the right thing, we'll fill in the ....s to finish filter-team-combinations. In the case where they conflict, we should drop the first team and recur on the rest. In the case where they don't conflict, we should cons the first team onto something.
(define (filter-team-combinations teams pair-pairs)
(cond [(empty? teams) (list)]
[else
(define new-pair-pairs (combinations (first teams) 2))
(cond [(pair-pairs-conflict? new-pair-pairs pair-pairs)
;; This team has a pair-pair that a previous team already had,
;; so don't include this team in the result; recur on the rest.
(filter-team-combinations (rest teams) pair-pairs)]
[else
;; Cons this team onto something.
(cons (first teams)
....)])]))
For the last ...., we need to recur on the rest, but we also need to make sure that the recursive call knows that the player-pairs in the first team shouldn't be on the same team again. To do that we can append them onto the pair-pairs argument.
;; filter-team-combinations : (Listof Team) (Listof Pair-Pair) -> (Listof Team)
;; Filters out teams where a player-pair would on a team with another
;; player-pair for the second time.
;; pair-pairs is an accumulator that stores the pair-pairs that we've
;; seen so far.
(define (filter-team-combinations teams pair-pairs)
(cond [(empty? teams) (list)]
[else
(define new-pair-pairs (combinations (first teams) 2))
(cond [(pair-pairs-conflict? new-pair-pairs pair-pairs)
;; This team has a pair-pair that a previous team already had,
;; so don't include this team in the result; recur on the rest.
(filter-team-combinations (rest teams) pair-pairs)]
[else
;; Add this team and add the new pair-pairs.
(cons (first teams)
(filter-team-combinations (rest teams)
(append new-pair-pairs pair-pairs)))])]))
So now we need to implement the pair-pairs-conflict? predicate.
;; pair-pairs-conflict? : (Listof Pair-Pair) (Listof Pair-Pair) -> Boolean
;; A team must be made up of sets of player-pairs that haven't been on the
;; same team yet. This function takes two lists of player-pair pairs.
;; Each pair-pair in the first list has two player-pairs that would now be
;; on the same team.
;; Each pair-pair in the second list has two player-pairs that have been
;; on the same team already.
;; This function returns true iff any player-pair would be on the same
;; team with anyone they have already been on the same team with.
(define (pair-pairs-conflict? as bs) ....)
It needs to take each pair-pair in the as and check whether it's in bs, and it conflicts if any a is in bs. One way to do that is with an ormap, and another way to do that is with for/or.
(define (pair-pairs-conflict? as bs)
(for/or ([a (in-list as)])
(member a bs)))
There's one problem with this though. The pair-pair (list 'a 'b) should be considered the same as the pair-pair (list 'b 'a). So we need a member function that doesn't care about this ordering thing. Luckily, member can take a third argument for it to use as an equality predicate.
(define (pair-pairs-conflict? as bs)
(for/or ([a (in-list as)])
(member a bs pair-pair=?)))
;; pair-pair=? : Pair-Pair Pair-Pair -> Boolean
(define (pair-pair=? a b)
(match-define (list a1 a2) a)
(match-define (list b1 b2) b)
(or (and (equal? a1 b1) (equal? a2 b2))
(and (equal? a1 b2) (equal? a2 b1))))
Now we have everything we need to find all the valid sets of teams.
(define teams (find-teams player-pairs))
To find matches, we need combinations of two teams, but we need to filter them to make sure that the teams are disjoint, so that a player-pair never plays against itself.
;; find-matches : (Listof Team) -> (Listof Match)
(define (find-matches teams)
(filter match-has-disjoint-teams? (combinations teams 2)))
;; match-has-disjoint-teams? : Match -> Boolean
(define (match-has-disjoint-teams? match)
(teams-disjoint? (first match) (second match)))
;; teams-disjoint? : Team Team -> Boolean
(define (teams-disjoint? team-1 team-2) ....)
To implement teams-disjoint?, we need to match every player-pair in team-1 against every player-pair in team-2 and make sure none of those are equal to each other. One way to do that would be with cartesian-product and andmap, but another way would be to use for*/and.
;; teams-disjoint? : Team Team -> Boolean
(define (teams-disjoint? team-1 team-2)
(for*/and ([p1 (in-list team-1)]
[p2 (in-list team-2)])
(not (equal? p1 p2))))
Using find-matches:
> (find-matches (list (list 'a 'b) (list 'b 'c) (list 'c 'd) (list 'd 'a)))
(list (list (list 'a 'b) (list 'c 'd))
(list (list 'b 'c) (list 'd 'a)))
> (find-matches (list (list 'a 'b 'c)
(list 'c 'd 'e)
(list 'e 'f 'g)
(list 'g 'h 'i)))
(list (list (list 'a 'b 'c) (list 'e 'f 'g))
(list (list 'a 'b 'c) (list 'g 'h 'i))
(list (list 'c 'd 'e) (list 'g 'h 'i)))
My attempted solution to question 1 was to compose find-matches with find-teams:
(find-matches (find-teams player-pairs))
With 24 different player-pairs, this produces 1,624 different match-ups.
Although, while two player-pairs would never be together on different teams, this includes match-ups where are together with the same team that they have been in in a different match-up.
That's probably not what you wanted. It might help you get there though, so I'll post it anyway.

Related

Functions operating on two lists

I am working on a Racket program for a class and I am totally stumped as to
how to implement one of the features.
The program uses Big-Bang and is supposed to implement a simple Space Invaders game.
I have everything working except one piece, and that is - how to handle the case
when a missile collides with an invader. The reason I'm struggling is that I don't
know how to write a function where I have two lists of arbitrary size, and I have
to check the fields of each object in one list with each object in another list and
remove an object in each list if they have the same values.
The world state is the game:
(define-struct game (invaders missiles tank))
where invaders and missiles are
both lists.
To produce the next state of the game, I implement a function called 'tock'.
Normally, I would just do:
(define (tock s)
(make-game (next-invaders (game-invaders s))
(next-missiles (game-missiles s))
(next-tank (game-tank s)))
But since the contents of the invaders and missiles lists might impact each other due to a collision, I can't simply update the positions independently and move on, I have to remove any collisions and then update the positions.
So I've tried:
(define (tock s)
(make-game (check-collision (game-invaders s)
(game-missiles s)
(game-tank s))
But this makes check-collision take a tank, which it doesn't need.
(define (tock s)
(make-game (next-invaders (game-invaders s) (game-missiles s))
(next-missiles (game-missiles s) (game-invaders s))
(next-tank (game-tank s))))
In this version, I have a function called next-invaders which takes the list of invaders and missiles, and a function
called next-missiles which takes the list of missiles and invaders. The first function checks each invader against each missile, attempts to remove any collided invaders and returns the remaining invaders. The second function checks each missile against each invader and attempts to remove any collided missiles and returns the remaining missiles. The answers should be the same, but it's duplicate work and I'm worried about a possible race condition. I don't know how else to construct a single expression where one function only needs two fields and the other one needs three
and I still wind up producing the next state of the game.
Here's an example of next-invaders. If there are no invaders, it does nothing. If there are invaders but no missiles,
it just moves each invader (move-invader) and recursively calls itself to iterate through all invaders. If there
are both missiles and invaders, then I check for a collision between the first invader in the list, and every
missile in the list; so check collision is recursive.
(define (next-invaders loi lom)
(cond [(empty? loi) empty]
[(empty? lom) (move-invader (first loi) (next-invaders (rest loi) lom))]
[(check_collision (first loi) lom)
(next-invaders (cons (rest loi) empty) lom)]
[else
(move-invader (first loi)
(next-invaders (rest loi) lom))]))
Is the 'answer' to check-collision the correct way to "remove" the collided invader from the list of invaders?
(define (check_collision i lom)
(cond [(empty? lom) false]
[(and (<= (- (missile-x (first lom)) (invader-x i)) HIT-RANGE)
(<= (- (missile-y (first lom)) (invader-y i)) HIT-RANGE))
true]
[else (check_collision i (rest lom))]))
Is this the correct way to test each element of each list against one another?
Update: Still going in circles on this problem. check-collision works and invader-function works, but when I return to missile-function, I don't know how to indicate that a missile needs to be deleted in the case where there was a collision detected in invader-function.
(define-struct invader (x y dx))
;; Invader is (make-invader Number Number Number)
;; interp. the invader is at (x, y) in screen coordinates
;; the invader along x by dx pixels per clock tick
(define-struct missile (x y))
;; Missile is (make-missile Number Number)
;; interp. the missile's location is x y in screen coordinates
(define-struct collision (invaders missiles))
(define (tock s)
(make-game (handle-invaders (collision-invaders (next-invaders-and-missiles (make-collision (game-invaders s) (game-missiles s)))))
(handle-missiles (collision-missiles (next-invaders-and-missiles (make-collision (game-invaders s) (game-missiles s)))))
(handle-tank (game-tank s))))
(define (next-invaders-and-missiles c)
(cond [(and (empty? (collision-invaders c)) (empty? (collision-missiles c))) (make-collision empty empty)]
[(or (empty? (collision-invaders c)) (empty? (collision-missiles c))) (make-collision (collision-invaders c) (collision-missiles c))]
[else
(missile-function (make-collision (collision-invaders c) (collision-missiles c)))]))
;; Collision -> list Of Missiles
;; produce an updated listOf Missiles taking collisions into account
(define (missile-function c)
(cond [(empty? (collision-missiles c)) (make-collision (collision-invaders c) empty)]
[else
(if (< (length (invader-function (first (collision-missiles c)) (collision-invaders c))) (length (collision-invaders c)))
(make-collision (collision-invaders c) (remove (first (collision-missiles c)) (collision-missiles c)))
(missile-function (make-collision (collision-invaders c) (rest (collision-missiles c)))))]))
;; Missile, listOf Invaders -> listOf Invaders
;; produce an updated listOf Invaders taking collisions into account
(define (invader-function m loi)
(cond [(empty? loi) empty]
[else
(if (check-collision? (first loi) m)
(remove (first loi) loi)
(invader-function m (rest loi)))]))
;; Invader, Missile -> Boolean
;; produce true if the coordinates of a missile are within HIT-RANGE of the coordinates of an invader
(define (check-collision? i m)
(and (<= (- (missile-x m) (invader-x i)) HIT-RANGE) (<= (- (missile-y m) (invader-y i)) HIT-RANGE)))
I haven't reviewed all the code, but the general solution is to have one function that takes the lists of missiles and invaders, checks for all the collisions, and then returns both updated lists by returning a pair of lists. So something like this:
(define (tock s)
(let* [(next (next-invaders-and-missiles (game-invaders s) (game-missiles s)))
(next-invaders (first next))
(next-missiles (rest next))]
(make-game next-invaders next-missiles (game-tank s))))
(define (next-invaders-and-missiles loi lom)
... ;; code that finds collisions and removes them from both lists
(cons new-loi new-lom))

Repeat the string list in Scheme language

I'm trying to make a code with Scheme language.I want to input a list and return the string representation of the list where the first element is repeated one time, the second element repeats two times and third element repeats three times like
input is => (c d g)
output is => (c d d g g g)
I wrote a code with duplicating all elements. I should use loop for making repeat all elements from first one to last one with 1 to n times.(n is size of list). But I do not know how.
(define repeat
(lambda (d)
(cond [(null? d) '()]
[(not (pair? (car d)))
(cons (car d)
(cons (car d)
(repeat (cdr d))))]
[else (cons (repeat (car d))
(repeat (cdr d)))])))
(repeat '(a b c d e)) => aa bb cc dd ee
(define size
(lambda (n)
(if (null? n)
0
(+ 1 (size (cdr n))))))
(size '(A B C D)) => 4
You will need to make a few different functions for this.
repeat (as you described) acts like this (repeat '(c d g)) ;=> (c d d g g g)
The best way to implement that is using a helper (repeat-aux n lst) which repeats the first element n times, the second element n+1 times and so on.
Given that you can define:
(define (repeat lst) (repeat-aux 1 lst))
To implement repeat-aux you can use a recursion pattern like this
(define (repeat-aux n lst)
(if (null? lst)
'()
... (repeat-aux (+ n 1) (cdr lst) ...))
I'm just giving a sketch or outline of the function, not the whole thing. So that you can work on it yourself.
To implement repeat-aux I would also recommend making a helping function (replicate n elt tail) which works like this:
(replicate 3 'o '(u v w)) ;=> (o o o u v w)
I hope the idea of breaking it down into simple helper function makes it easier. Have a go and feel free to ask if you get stuck.

Solving a puzzle in Racket

I tried to solve this puzzle https://puzzling.stackexchange.com/questions/40094/who-committed-the-crime using Racket.
A crime has been carried out by one person, there are 5 suspects. Each
suspect is asked under polygraph who they think committed the crime.
Their answers are as follows:
Terry : It wasn't Carl, It was Steve
Steve : It wasn't Matt, It wasn't Carl
Matt : It was Carl, It wasn't Terry
Ben : It was Matt, It was Steve
Carl : It was Ben, It wasn't Terry
The polygraph showed that
each suspect told one lie and one truth. Who committed the crime?
Following is my code:
(define (oneof a b)
(or (and a (not b)) (and b (not a))))
(for ((i 5))
(define templist (list #f #f #f #f #f)) ; make a temporary list of all false;
(set! templist (list-set templist i #t)) ; one by one keep one as true in this loop;
(define t (list-ref templist 0)) ; allocate each person according to above list (one kept true one by one)
(define s (list-ref templist 1))
(define m (list-ref templist 2))
(define b (list-ref templist 3))
(define c (list-ref templist 4))
(when ; test if all statements fit with above assignment:
(and
(oneof (not c) s) ; Terry's statement
(oneof (not m) (not c)) ; Steve's statement
(oneof c (not t)) ; Matt's statement
(oneof m s) ; Ben's statement
(oneof b (not t))) ; Carl's statement
(println (list "t" "s" "m" "b" "c")) ; print allocation if all statement fit in;
(println templist)))
Output indicates Matt committed the crime:
'("t" "s" "m" "b" "c")
'(#f #f #t #f #f)
It works but the code is imperative and not very functional (especially define t, define s, ... part). How can it can be improved? Thanks for your comments/answers.
This answer is based on #Oscar Lopez's answer, but modified to use more idiomatic features like filter with a helper function instead of for, when, and println.
This style of code returning a value is much more useful because the value it produces could be used in later code, where an imperative action like println would be much less reusable.
#Oscar Lopez's make-matrix function produces an initial list of possibilities, but we have to filter out the ones that are impossible, and leave only the ones that are possible. So write that down:
;; If there are no valid solutions, this will be an empty list,
;; if there's one, this will be a list of one element,
;; and if there are more, this will include all of them.
(filter valid-solution? (make-matrix 5))
;; Wish list:
;; valid-solution? : (Listof Boolean) -> Boolean
Now we just need to add a definition for valid-solution?
;; valid-solution? : (Listof Boolean) -> Boolean
;; Given a list containing booleans for whether Terry, Steve, Matt, Ben, and Carl did it,
;; this determines whether that combination is possible under the constraints in the problem.
(define (valid-solution? row)
; unpack each row into the corresponding variables
(match-define (list t s m b c) row)
; don't reinvent the wheel, `oneof` is called `xor`
(and (xor (not c) s)
(xor (not m) (not c))
(xor c (not t))
(xor m s)
(xor b (not t))))
And that's it. The full program including make-matrix is this:
#lang racket
;; make-matrix : Natural -> (Listof (Listof Boolean))
;; generate a matrix with possibilities
(define (make-matrix n)
(for/list ([i (in-range n)])
(build-list n (λ (j) (= i j)))))
;; valid-solution? : (Listof Boolean) -> Boolean
;; Given a list containing booleans for whether Terry, Steve, Matt, Ben, and Carl did it,
;; this determines whether that combination is possible under the constraints in the problem.
(define (valid-solution? row)
; unpack each row into the corresponding variables
(match-define (list t s m b c) row)
; don't reinvent the wheel, `oneof` is called `xor`
(and (xor (not c) s)
(xor (not m) (not c))
(xor c (not t))
(xor m s)
(xor b (not t))))
;; If there are no valid solutions, this will be an empty list,
;; if there's one, this will be a list of one element,
;; and if there are more, this will include all of them.
(filter valid-solution? (make-matrix 5))
This is an equivalent program written in idiomatic Racket - and avoiding all those pesky set! and list-ref which are frowned upon when writing functional-style code:
; generate a matrix with possibilities
(define (make-matrix n)
(for/list [(i (in-range n))]
(build-list n (λ (j) (= i j)))))
; iterate over each row
(for [(row (make-matrix 5))]
; unpack each row into the corresponding variables
(match-let ([(list t s m b c) row])
; don't reinvent the wheel, `oneof` is called `xor`
(when (and (xor (not c) s)
(xor (not m) (not c))
(xor c (not t))
(xor m s)
(xor b (not t)))
(println '(t s m b c))
(println row))))

Scheme - checking structural equivalences of lists (how to use AND)

I am trying to write a program that will check the structural equivalence of some list input, whether it includes just atoms or nested sub lists.
I am having trouble with using AND, I don't even know if its possible and I cant seem to understand documentation I am looking at.
My code:
(define (structEqual a b)
(cond
(((null? car a) AND (null? car b)) (structEqual (cdr a) (cdr b)))
(((null? car a) OR (null? car b)) #f)
(((pair? car a) AND (pair? car b))
(if (= (length car a) (length car b))
(structEqual (cdr a) (cdr b))
#f))
(((pair? car a) OR (pair? car b)) #f)
(else (structEqual (cdr a) (cdr b)))))
The idea is (i think): (when I say both, i mean the current cdr of a or b)
Check if both a and b are null, then they are structurally equal
Check if only either a or b is null, then they are not structually equal
Check if both of them are pairs
If they are both pairs, then see if the length of the pair is equal, if not they are not structurally equal.
If they are not both pairs, then if one of them is a pair and the other isnt then they are not structurally equivalent.
If neither of them are pairs, then they both must be atoms, so they are structurally equivalent.
So as you can see I am trying to recursively do this by checking the equivalence of the car of a or b, and then either returning #f if they fail or moving on to the cdr of each if they are equivalent at each step.
Any help?
There is no infix operators in Scheme (or any LISP) only prefix. Every time the operator comes first. (or x (and y z q) (and y w e)) where each letter can be a complex expression. Everything that is not #f is a true value. Thus (if 4 'a 'b) evaluates to a because 4 is a true value. car needs its parentheses.
When evaluating another predicate in cond you should make use of the fact that everything up to that has been false. eg.
(define (structure-equal? a b)
(cond
((null? a) (null? b)) ; if a is null the result is if b is null
((not (pair? a)) (not (pair? b))) ; if a is not pair the result is if b is not also
((pair? b) (and (structure-equal? (car a) (car b)) ; if b is pair (both a and b is pair then) both
(structure-equal? (cdr a) (cdr b)))) ; car and cdr needs to be structurally equal
(else #f))) ; one pair the other not makes it #f
(structure-equal '(a (b (c d e) f) g . h) '(h (g (f e d) c) b . a)) ; ==> #t

Scheme How To Return Multiple Values?

I notice that almost all scheme functions can only return one list as output.
In the following, I would like to return multiple values of all the adjacent nodes of neighbors.
(define (neighbors l w)
(if (and (= 1 l) (= 1 w))
(list (and (l (+ 1 w))) (and (+ 1 l) w)))) ; how to output 2 or more values?
In this case I'm first testing if the node is at corner, if so, return 2 values of the coordinates where (l and w+1), (l+1 and w) basically if I'm at (1,1) return me (1,2) and (2,1)
Same applies when the node has only 1 neighbor near the edge, in this case I will have 3 values.
When no edge is nearby I will have 4 return values.
I tried to use cons, append, list, display, write none of them seems working with additional values. I need this as a sub-function of this question. How should I implement it so I could pass on the return value and use it recursively to return me all the adjacent nodes?
Edit: I found the answer: use the keyword "values" to return multiple values. Example:
(define (store l w)
(values (write l)
(write w)
(newline)
(list (+ 1 w) l)
(list w (+ 1 l))))
values, continuation passing style, and list are at least three ways of returning multiple values:
(import (rnrs))
; let-values + values
(define (foo1)
(values 1 2 3))
(let-values (((a b c) (foo1)))
(display (list a b c))
(newline))
; cps
(define (foo2 k)
(k 1 2 3))
(foo2 (lambda (a b c)
(display (list a b c))
(newline)))
; list
(define (foo3)
(list 1 2 3))
(let ((result (foo3)))
(display result)
(newline))
The Guile implementation of Scheme has a receive syntax, which it says is "much more convenient" than values. I haven't used it yet, however, but this may be useful:
http://www.gnu.org/software/guile/manual/html_node/Multiple-Values.html
You can return a pair of values in a cons cell:
(define (foo)
(cons 'a 5))
(let* ((r (foo))
(x (car r))
(y (cdr r)))
(display x) (display y) (newline))
You can generalise this to return multiple values in a list, too.

Resources