Background
I have this current program in scheme
(define (tsar subj srch repl)
(cond
((list? subj)
(map
(lambda (lst) (tsar lst srch repl))
subj))
(else
(if (equal? subj repl)
srch
subj))))
This function takes a subject subj
as a parameter (generally speaking this is should be a list), a value to search for in the list srch
and a value to replace the value with repl
Now generally, this function works:
for instance:
(display(tsar '(1 2 () 4 (7 (7 (3 7)))) '() 3))
yields
(1 2 () 4 (7 (7 (() 7))))
the atom 3
in the list is replaced with ()
as expected.
The problem
There's another twist to this program that I need to resolve, in situations where the atom RANDOM
is contained in the list we need to replace that atom with a random number between 0-100 by using (random 100)
.
What I know (or think I know)
I know I should probably use eq?
or something similar to determine whether an atom is RANDOM or not. I also know (perhaps) that I can probably recursively use the tsar
function to achieve this by passing in the list as subj
, RANDOM
as srch
and (random 100)
as repl
.
I'm having an absolute doozy trying to wrap my head around how to make this happen (I am almost completely new to scheme and functional programming in general)
For clarification purposes RANDOM is not a string it is a symbol
CodePudding user response:
In general, you could test for that specific symbol by quoting, then return either the result of (random 100) -- assuming (random 100) returns a result between 0 and 100 in your scheme, this is apparantly not standard -- or else the subject again:
(if (eq? subj 'random)
(random 100)
subj))
And you would put this (eq? subj 'RANDOM) as a clause in your function's COND statement:
(define (tsar subj srch repl)
(cond
((list? subj)
(map
(lambda (lst) (tsar lst srch repl))
subj))
((eq? subj 'random)
(random 100))
(else
(if (equal? subj repl)
srch
subj))))
(edited out an extraneous 'if' condition.)
As an aside: at least the Scheme I tested on, BiwaScheme, has caps-specific symbols, so 'random, 'Random, 'RANDOM, etc. all test false with each other, and you would need a COND clause for each symbol. I'm not sure how to combine them to the general case.
CodePudding user response:
My suspicion is you have srch
and repl
backwards: do you really want to replace repl
by srch
? You are also using cond
in a non-idiomatic way: you don't need to write
(cond
...
(else (if x y z)))
Because the body of cond
itself is a bunch of conditionals and results, so you can just turn that into
(cond
...
(x y)
(else z))
So here is your function with those things changed (this is Racket you may need to change [...]
to (...)
and λ
to lambda
):
(define (tsar subj srch repl)
(cond
[(list? subj)
(map (λ (lst) (tsar lst srch repl)) subj)]
[(equal? subj srch)
repl]
[else subj]))
Now, OK to fix this to check for RANDOM
we need another clause in the cond
which checks for RANDOM
. I'm not going to write it but its test will be (eqv? subj 'RANDOM)
and the result will be, probably (random 100)
.
CodePudding user response:
Tested it using mit-scheme
:
1 ]=> (fold-right (lambda (x a) (if (eq? x 'random) (cons (random 100) a) (cons x a))) '() '(1 2 3))
;Value: (1 2 3)
1 ]=> (fold-right (lambda (x a) (if (eq? x 'random) (cons (random 100) a) (cons x a))) '() '(1 random 3))
;Value: (1 38 3)
1 ]=> (fold-right (lambda (x a) (if (eq? x 'random) (cons (random 100) a) (cons x a))) '() '(1 random random))
;Value: (1 97 50)
So you can do something like:
(define (doit input)
(fold-right
(lambda (x a)
(if (eq? x 'random)
(cons (random 100) a)
(cons x a)))
'()
input)