What I'm trying to do is shown below in pseudo code:
case (test0, test1)
begin
(false,false): statement 0;
(false,true): statement 1;
(true,false): statement 2;
(true,true): statement 3;
end
How to do it in scheme using the case conditional? The problem is that case uses the eqv? predicate which it seems will always return false (because (eqv? '(#f . #f) '(#f . #f)) evaluates to #f). Would appreciate any reasonably concise way of expressing above pattern in scheme (other than the obvious breaking it down into nested if conditionals).
Edit: Valid answers below lead me to reframe my query slightly: how would a seasoned schemer code up the above pattern?
This seems like a good fit for Racket's match:
(define (test pair)
(match pair
['(#f . #f) "statement 1"]
['(#f . #t) "statement 2"]
['(#t . #f) "statement 3"]
['(#t . #t) "statement 4"]
[else (error "unknown expression:" pair)]))
For example:
(test '(#t . #f))
=> "statement 3"
(test (cons (= 0 0) (= 1 1)))
=> "statement 4"
(test '(a . b))
=> unknown expression: (a . b)
It's easier to use cond and equal?:
(define (test pair)
(cond
((equal? pair '(#f . #f)) "statement 0")
((equal? pair '(#f . #t)) "statement 1")
((equal? pair '(#t . #f)) "statement 2")
((equal? pair '(#t . #t)) "statement 3")
(else "wot?")))
One way, illustrating an approach:
(case (+ (if test0 10 0) (if test1 1 0))
((11) …)
((10) …)
((01) …)
((00) …))
How would I actually do it… If there is any asymmetry in the importance between test0 and test1 I would simply use if with the most important test first. As such, assuming test0 is more important:
(if test0
(if test1
… ;; (and test0 test1)
…) ;; (and test0 (not test1))
(if test1
… ;; …
…)) ;; …
If there is no difference whatsoever in importance, then:
(cond ((and test0 test1) …)
((and test0 (not test1)) …)
…)
If it is a common pattern with two variables, then I'd define a macro that allows me to specify the four bodies within a lexical binding of test0 and test1:
(define-syntax if-two-way
(syntax-rules (tt tf ft ff)
((if-two-way test0 test1
(tt btt1 btt …)
(tf btf1 btf …)
(ft bft1 bft …)
(ff bgg1 bff …))
(let ((t0 test0) (t1 test1))
(if t0
(if t1
(begin btt1 btt …)
(begin btf1 btf …))
…))))))
Related
I am trying to implement a dictionary using lists in Common Lisp. The program is supposed to take a list of words and create a word histogram with frequency of each unique word.
This is the program:
(defparameter *histo* '())
(defun scanList (list)
(loop for word in list
do (if (assoc word histo)
((setf pair (assoc word histo))
(remove pair histo)
(setf f (+ 1 (second pair)))
(setf pair ((car pair) f))
(append histo pair))
((setf pair (word '1)) (append histo pair)))))
The error I get is: (SETF PAIR (ASSOC WORD *HISTO*)) should be a lambda expression.
Where is the syntax or semantic error exactly ?
(defun scanList (list the fox jumped over the other fox))
(princ *histo*)
Use hash-table for creating the dictionary and then transform to an association-list (alist) to sort it by key or value.
(defun build-histo (l)
(let ((dict (make-hash-table :test 'equal)))
(loop for word in l
do (incf (gethash word dict))
finally (return dict))))
;; which was simplification (by #Renzo) of
;; (defun build-histo (l)
;; (let ((dict (make-hash-table :test 'equal)))
;; (loop for word in l
;; for count = (1+ (gethash word dict 0))
;; do (setf (gethash word dict) count)
;; finally (return dict))))
(defparameter *histo* (build-histo '("a" "b" "c" "a" "a" "b" "b" "b")))
(defun hash-table-to-alist (ht)
(maphash #'(lambda (k v) (cons k v)) ht))
;; which is the same like:
;; (defun hash-table-to-alist (ht)
;; (loop for k being each hash-key of ht
;; for v = (gethash k ht)
;; collect (cons k v)))
;; sort the alist ascending by value
(sort (hash-table-to-alist *histo*) #'< :key #'cdr)
;; => (("c" . 1) ("a" . 3) ("b" . 4))
;; sort the alist descending by value
(sort (hash-table-to-alist *histo*) #'> :key #'cdr)
;; => (("b" . 4) ("a" . 3) ("c" . 1))
;; sort the alist ascending by key
(sort (hash-table-to-alist *histo*) #'string< :key #'car)
;; => (("a" . 3) ("b" . 4) ("c" . 1))
;; sort the alist descending by key
(sort (hash-table-to-alist *histo*) #'string> :eky #'car)
;; => (("c" . 1) ("b" . 4) ("a" . 3))
The posted code has a whole lot of problems. The reported error is caused by superfluous parentheses. Parentheses can't be added arbitrarily to expressions in Lisps without causing problems. In this case, these are the offending expressions:
((setf pair (assoc word histo))
(remove pair histo)
(setf f (+ 1 (second pair)))
(setf pair ((car pair) f)
(append histo pair))
((setf pair (word '1)) (append histo pair))
In both of these expressions, the results of the calls to setf are placed in the function position of a list, so the code attempts to call that result as if it is a function, leading to the error.
There are other issues. It looks like OP code is trying to pack expressions into the arms of an if form; this is probably the origin of the extra parentheses noted above. But, if forms can only take a single expression in each arm. You can wrap multiple expressions in a progn form, or use a cond instead (which does allow multiple expressions in each arm). There are some typos: *histo* is mistyped as histo in most of the code; f and pair are not defined anyplace; (setf pair (word '1)) quotes the 1 unnecessarily (which will work, but is semantically wrong).
Altogether, the code looks rather convoluted. This can be made much simpler, still following the same basic idea:
(defparameter *histo* '())
(defun build-histogram (words)
(loop :for word :in words
:if (assoc word *histo*)
:do (incf (cdr (assoc word *histo*)))
:else
:do (push (cons word 1) *histo*)))
This code is almost self-explanatory. If a word has already been added to *histo*, increment its counter. Otherwise add a new entry with the counter initialized to 1. This code isn't ideal, since it uses a global variable to store the frequency counts. A better solution would construct a new list of frequency counts and return that:
(defun build-histogram (words)
(let ((hist '()))
(loop :for word :in words
:if (assoc word hist)
:do (incf (cdr (assoc word hist)))
:else
:do (push (cons word 1) hist))
hist))
Of course, there are all kinds of other ways you might go about solving this.
I want to apply or to every element of list, example:
(apply or '(#t #t #f)) expected result #t, but I'm getting error:
'#' to 'apply' has wrong type (kawa.lang.Macro) (expected: procedure, sequence, or other operator)
As I understand or is not a procedure.
Is there any procedure that can be used instead of or?
The easiest way to do this is with exists*. Whenever you would use (apply or some-list), you can use (exists values some-list). Or if you like, you can define a function that uses exists to do that:
#!r6rs
(import (rnrs base)
(rnrs lists))
(define (or* . lst)
(exists values lst))
values is the identity function, so (values x) is just x.
exists is a higher-order function defined so that (exists f (list x ...)) is equivalent to (or (f x) ...).
For example (exists values (list #t #t #f)) is equivalent to (or (values #t) (values #t) (values #f)), which is the same as (or #t #t #f).
Trying it out:
> (apply or* '(#t #t #f))
#t
> (apply or* '(#f #f #f))
#f
> (or* #t #t #f)
#t
> (or*)
#f
*exists is sometimes known as ormap or any
In SRFI-1 List Library you have every and any which basically is and and or for a procedure over a list.
#!r6rs
(import (rnrs base)
(only (srfi :1) every any)
(define num1-10 '(1 2 3 4 5 6 7 8 9 10))
(define odd1-9 '(1 3 5 7 9))
(every odd? num1-10) ; ==> #f
(any odd? num1-10) ; ==> #t
(every odd? odd1-9) ; ==> #t
For a list of booleans the procedure only need to return the argument. values returns it's argument and serve as identity:
(define booleans '(#f #t))
(every values booleans) ; ==> #f
(any values booleans) ; ==> #t
SRFI-1 is a safe choice as it is the list library of the upcoming R7RS Red edition. In many R5RS and R6RS implementations SRFI-1 is included and you can easily add it from the SRFI reference implementation if it isn't. In DrRacket's default language DrRacket, that has ormap and andmap, you can opt to use SRFI-1 instead by importing them with (require srfi/1).
You could define your own procedure that uses or
(define (orp . ls)
(if (null? ls) #f
(if (< (length ls) 2) (car ls) (or (car ls) (orp (cdr ls))))))
And use it:
(apply orp '(#t #f #t))
The main point is that or (and if, cond, and ....) operator has lazy evaluation semantics. Hence (or #t (/ 1 0)) does not make a division by zero. Because of that or cannot be an ordinary function.
You might code a lambda to force the eager evaluation, e.g. define your eager-or variadic function, and apply that.
I wish to replace the first occurrence of a symbol within pairs. For example:
take
(define n '((a . b) . (a . d)))
and i define a method context to replace the first instance (left most) of X with '()
replacing a should give me:
((() . b) a . d)
however i am stuck as my method replaces ALL instances and i am not sure how to add a check for this.
my code is as follows:
(define (context s sym)
(cond ((null? s) #f)
((atom? s)
(if (equal? s sym) '() s ))
(else (cons (context (car s) sym)
(context (cdr s) sym)))))
which gives : ((() . b) () . d)
any help? Thank you
The quickest way is to use a flag indicating whether the replacement has already been done, something along the lines of:
(define (context sxp sym)
(define done #f)
(let loop ((sxp sxp))
(cond (done sxp)
((pair? sxp) (cons (loop (car sxp)) (loop (cdr sxp))))
((eq? sym sxp) (set! done #t) '())
(else sxp))))
It's not very elegant to use set!, but the alternative would be to have the procedure return 2 values, and the resulting let-values code would be even worse in terms of readability IMO.
Also note that I didn't use atom? because it's not defined in standard Scheme; the usual way is to successively test null? then pair?, and handle the atom case in the else clause.
This is a bit more general (you can replace things other than symbols, and you can customize the test, and you can specify any particular number of instances to replace, not just one), and may be a little bit more complicated at first glance than what you're looking for, but here's a solution that works by internally using a continuation-passing style helper function. The main function, subst-n takes a new element, and old element, a tree, a test, and a count. It replaces the first count occurrences of new (as compared with test) with old (or all, if count is not a non-negative integer).
(define (subst-n new old tree test count)
(let substs ((tree tree)
(count count)
(k (lambda (tree count) tree)))
(cond
;; If count is a number and zero, we've replaced enough
;; and can just "return" this tree unchanged.
((and (number? count) (zero? count))
(k tree count))
;; If the tree is the old element, then "return" the new
;; element, with a decremented count (if count is a number).
((test old tree)
(k new (if (number? count) (- count 1) count)))
;; If tree is a pair, then recurse on the left side,
;; with a continuation that will recurse on the right
;; side, and then put the sides together.
((pair? tree)
(substs (car tree) count
(lambda (left count)
(substs (cdr tree) count
(lambda (right count)
(k (cons left right) count))))))
;; Otherwise, there's nothing to do but return this
;; tree with the unchanged count.
(else
(k tree count)))))
> (display (subst-n '() 'a '((a . b) . (a . d)) eq? 1))
((() . b) a . d)
> (display (subst-n '() 'a '((a . b) . (a . d)) eq? 2))
((() . b) () . d)
I'm quite new to functional programming, especially Scheme as used below. I'm trying to make the following function that is recursive, tail recursive.
Basically, what the function does, is scores the alignment of two strings. When given two strings as input, it compares each "column" of characters and accumulates a score for that alignment, based on a scoring scheme that is implemented in a function called scorer that is called by the function in the code below.
I sort of have an idea of using a helper function to accumulate the score, but I'm not too sure how to do that, hence how would I go about making the function below tail-recursive?
(define (alignment-score string_one string_two)
(if (and (not (= (string-length string_one) 0))
(not (=(string-length string_two) 0)))
(+ (scorer (string-ref string_one 0)
(string-ref string_two 0))
(alignment-score-not-tail
(substring string_one 1 (string-length string_one))
(substring string_two 1 (string-length string_two))
)
)
0)
)
Just wanted to make an variant of Chris' answer that uses lists of chars:
(define (alignment-score s1 s2)
(let loop ((score 0)
(l1 (string->list s1))
(l2 (string->list s2)))
(if (or (null? l1) (null? l2))
score
(loop (+ score (scorer (car l1)
(car l2)))
(cdr l1)
(cdr l2)))))
No use stopping there. Since this now have become list iteration we can use higher order procedure. Typically we want a fold-left or foldl and SRFI-1 fold is an implementation of that that doesn't require the lists to be of the same length:
; (import (scheme) (only (srfi :1) fold)) ; r7rs
; (import (rnrs) (only (srfi :1) fold)) ; r6rs
; (require srfi/1) ; racket
(define (alignment-score s1 s2)
(fold (lambda (a b acc)
(+ acc (scorer a b)))
0
(string->list s1)
(string->list s2)))
If you accumulating and the order doesn't matter always choose a left fold since it's always tail recursive in Scheme.
Here's how it would look like with accumulator:
(define (alignment-score s1 s2)
(define min-length (min (string-length s1) (string-length s2)))
(let loop ((score 0)
(index 0))
(if (= index min-length)
score
(loop (+ score (scorer (string-ref s1 index)
(string-ref s2 index)))
(+ index 1)))))
In this case, score is the accumulator, which starts as 0. We also have an index (also starting as 0) that keeps track of which position in the string to grab. The base case, when we reach the end of either string, is to return the accumulated score so far.
I trying to write a function which gets an integer number , represented by string , and check if all his chars are digits and return #t \ #f accordingly . Thats the code -
(define (splitString str) (list->vector (string->list str)))
(define myVector 0)
(define flag #t)
(define (checkIfStringLegal str) (
(set! myVector (splitString str))
(do ( (i 0 (+ i 1)) ) ; init
((= i (vector-length myVector)) flag) ; stop condition
(cond ((>= 48 (char->integer (vector-ref myVector i)) ) (set! flag #f))
((<= 57 (char->integer (vector-ref myVector i)) )(set! flag #f))
)
)
)
)
Few explanations -
(list->vector (string->list str)) - convert string the char list .
(vector-ref myVector i) - char from the myVector at place i .
Its run OK , but when I try to use this func , like (checkIfStringLegal "444") I get -
application: not a procedure;
expected a procedure that can be applied to arguments
given: #<void>
arguments...:
#t
Try this:
(define (checkIfStringLegal str)
(andmap char-numeric?
(string->list str)))
This is how the procedure works:
It transforms the string into a list of characters, using string->list
It validates each character in the list to see if it's a number, applying the predicate char-numeric? to each one
If all the validations returned #t, andmap will return #t. If a single validation failed, andmap will return #f immediately
That's a functional-programming solution (and after all, this question is tagged as such), notice that your intended approach looks more like a solution in a C-like programming language - using vectors, explicit looping constructs (do), mutation operations (set!), global mutable definitions ... that's fine and it might eventually work after some tweaking, but it's not the idiomatic way to do things in Scheme, and it's not even remotely a functional-programming solution.
EDIT:
Oh heck, I give up. If you want to write the solution your way, this will work - you had a parenthesis problem, and please take good notice of the proper way to indent and close parenthesis in Scheme, it will make your code more readable for you and for others:
(define (splitString str) (list->vector (string->list str)))
(define myVector 0)
(define flag #t)
(define (checkIfStringLegal str)
(set! myVector (splitString str))
(do ((i 0 (+ i 1)))
((= i (vector-length myVector)) flag)
(cond ((>= 48 (char->integer (vector-ref myVector i)))
(set! flag #f))
((<= 57 (char->integer (vector-ref myVector i)))
(set! flag #f)))))
Even so, the code could be further improved, I'll leave that as an exercise for the reader:
Both conditions can be collapsed into a single condition, using an or
The exit condition should be: end the loop when the end of the vector is reached or the flag is false