I've just started to learn Racket.
I have this code:
#lang racket
(define t1 '(10 20))
(define t2 '(20 30))
(if (list? (first t1)) (define funcion1 >=) (define funcion1 >))
(if (list? (last t1)) (define funcion2 <=) (define funcion2 <))
(not (and (function1 (first t2) (first t1))
(function2 (last t2) (last t1))))
But it doesn't work because Racket doesn't allow this: (define funcion1 >=). I get the error:
define: not allowed in an expression context in: (define funcion1 >=)
Instead of doing nested if, I have thought to use a generic id (function1 and function2) for the function > and <.
NOTE: t1 could be also(define t1 '((20) 35)).
How can I fix this error?
define is different top level and inside a function. Also while you cannot put define in side a if you can put if inside the expression of a define:
This is totally OK:
(define function1 (if (list? (first t1)) >= >))
(define function2 (if (list? (last t1)) <= <))
Using let is also OK, but then you can only them withing the closure it creates:
(let ([function1 (if (list? (first t1)) >= >)]
[function2 (if (list? (last t1)) <= <)])
;; use function1 and function2 here
)
;; function1 and function2 no longer exists here
Same with local define:
(let () ;; this is a function called right away
;; these are local define
(define function1 (if (list? (first t1)) >= >))
(define function2 (if (list? (last t1)) <= <))
;; use function1 and function2 here
)
;; function1 and function2 no longer exists here
This is just fancy way of writing:
(let ()
(letrec ([function1 (if (list? (first t1)) >= >)]
[function2 (if (list? (last t1)) <= <)])
;; use function1 and function2 here
)
;; use function1 and function2 here
)
The let in the last example is redundant and just there because the previous example had it.
I think I have found how to fix this problem with the inspiration of this SO answer: using let.
#lang racket
(define t1 '(10 20))
(define t2 '(20 30))
(let ([function1 (if (list? (first t1)) >= >)])
(let ([function2 (if (list? (last t1)) <= <)])
(not (and (function1 (first t2) (first t1))
(function2 (last t2) (last t1))))))
But maybe there is a better way to do it.
Related
I am simply trying to make this average function to be tail recursive. I have managed to get my function to work and that took some considerable effort. Afterwards I went to ask my professor if my work was satisfactory and he informed me that
my avg function was not tail recursive
avg did not produce the correct output for lists with more than one element
I have been playing around with this code for the past 2 hours and have hit a bit of a wall. Can anyone help me to identify what I am not understanding here.
Spoke to my professor he was != helpful
(defun avg (aList)
(defun sumup (aList)
(if (equal aList nil) 0
; if aList equals nil nothing to sum
(+ (car aList) (sumup (cdr aList)) )
)
)
(if
(equal aList nil) 0
; if aList equals nil length dosent matter
(/ (sumup aList) (list-length aList) )
)
)
(print (avg '(2 4 6 8 19))) ;39/5
my expected results for my test are commented right after it 39/5
So this is what I have now
(defun avg (aList &optional (sum 0) (length 0))
(if aList
(avg (cdr aList) (+ sum (car aList))
(+ length 1))
(/ sum length)))
(print (avg '(2 4 6 8 19))) ;39/5
(defun avg (list &optional (sum 0) (n 0))
(cond ((null list) (/ sum n))
(t (avg (cdr list)
(+ sum (car list))
(+ 1 n)))))
which is the same like:
(defun avg (list &optional (sum 0) (n 0))
(if (null list)
(/ sum n)
(avg (cdr list)
(+ sum (car list))
(+ 1 n))))
or more similar for your writing:
(defun avg (list &optional (sum 0) (n 0))
(if list
(avg (cdr list)
(+ sum (car list))
(+ 1 n))
(/ sum n)))
(defun avg (lst &optional (sum 0) (len 0))
(if (null lst)
(/ sum len)
(avg (cdr lst) (incf sum (car lst)) (1+ len))))
You could improve your indentation here by putting the entire if-then/if-else statement on the same line, because in your code when you call the avg function recursively the indentation bleeds into the next line. In the first function you could say that if the list if null (which is the base case of the recursive function) you can divide the sum by the length of the list. If it is not null, you can obviously pass the cdr of the list, the sum so far by incrementing it by the car of the list, and then increment the length of the list by one. Normally it would not be wise to use the incf or 1+ functions because they are destructive, but in this case they will only have a localized effect because they only impact the optional sum and len parameters for this particular function, and not the structure of the original list (or else I would have passed a copy of the list).
Another option would be to use a recursive local function, and avoid the optional parameters and not have to compute the length of the list on each recursive call. In your original code it looks like you were attempting to use a local function within the context of your avg function, but you should use the "labels" Special operator to do that, and not "defun":
(defun avg (lst)
(if (null lst)
0
(labels ((find-avg (lst sum len)
(if (null lst)
(/ sum len)
(find-avg (cdr lst) (incf sum (car lst)) len))))
(find-avg lst 0 (length lst))))
I'm not 100% sure if your professor would want the local function to be tail-recursive or if he was referring to the global function (avg), but that is how you could also make the local function tail-recursive if that is an acceptable remedy as well. It's actually more efficient in some ways, although it requires more lines of code. In this case a lambda expression could also work, BUT since they do not have a name tail-recursion is not possibly, which makes the labels Special operator is useful for local functions if tail-recursion is mandatory.
I am totally new to Lisp.
How to find the difference between elements in an arithmetic progression series?
e.g.
(counted-by-N '(20 10 0))
Return -10
(counted-by-N '(20 10 5))
(counted-by-N '(2))
(counted-by-N '())
Returns Nil
In Python/C and other languages, it is very straightforward... Kinda stuck here in Lisp.
My pseudo algorithm would be something like this:
function counted-by-N(L):
if len(L) <= 1:
return Nil
else:
diff = L[second] - L[first]
for (i = second; i < len(L) - 1; i++):
if L[i+1] - L[i] != diff
return Nil
return diff
Current work:
(defun count-by-N (L)
(if (<= (length L) 1) Nil
(
(defvar diff (- (second L) (first L)))
; How to do the loop part?
))
)
(flet ((by-n (list &aux
(e1 (first list))
(e2 (second list))
(difference (and e1 e2 (- e2 e1))))
(and difference
(loop for (one two) on list
while (and one two)
when (/= (- two one) difference)
do (return-from by-n nil)))
difference))
(by-n '(20 10 0)))
or
(flet ((by-n (list &aux
(e1 (first list))
(e2 (second list))
(difference (and e1 e2 (- e2 e1))))
(when difference
(loop for (one two) on list
while (and one two)
when (/= (- two one) difference)
do (return-from by-n nil))
difference)))
(by-n '(20 10 0)))
As far as you said on the second answer the best choice you have to do this example is implement it recursively.
Example Using List Processing (good manners)
That way, you have some ways to do this example on the recursively and simple way:
(defun count-by-N-1 (lst)
(if (equal NIL lst)
NIL
(- (car (cdr lst)) (car lst))
)
(count-by-N-1 (cdr lst))
)
On this first approach of the function count-by-N-1 I am using the simple car and cdr instructions to simplify the basics of Common Lisp List transformations.
Example Using List Processing Shortcuts (best implementation)
However you can resume by using some shortcuts of the car and cdr instructions like when you want to do a a car of a cdr, like I did on this example:
(defun count-by-N-2 (lst)
(if (equal NIL lst)
NIL
(- (cadr lst) (car lst))
)
(count-by-N-2 (cdr lst))
)
If you have some problems to understand this kind of questions using basic instructions of Common Lisp List transformation as well as car and cdr, you still can choose the first, second and rest approach. However I recommend you to see some of this basic instructions first:
http://www.gigamonkeys.com/book/they-called-it-lisp-for-a-reason-list-processing.html
Example Using Accessors (best for understand)
(defun count-by-N-3 (lst)
(if (equal NIL lst)
NIL
(- (first (rest lst)) (first lst))
)
(count-by-N-3 (rest lst))
)
This last one, the one that I will explain more clearly since it is the most understandable, you will do a recursion list manipulation (as in the others examples), and like the others, until the list is not NIL it will get the first element of the rest of the list and subtract the first element of the same list. The program will do this for every element till the list is "clean". And at last returns the list with the subtracted values.
That way if you read and study the similarities between using first, second and rest approach against using car and cdr, you easily will understand the both two first examples that I did put here.
Here is my final answer of this question which uses recursion:
(defun diff (N)
(- (second N) (first N))
)
(defun count-by-N (L)
(cond
((null L) nil)
((= (length L) 1) nil)
((= (length L) 2) (diff L))
((= (diff L) (diff (rest L))) (count-by-N (rest L)))
(T nil)
)
)
clisp:
(defun sorted (seq comp)
(or
(< (length seq) 2)
(and (comp (car seq) (car seq))
(sorted (cdr seq) comp)
)
))
on ubuntu, run clisp :
(sorted '(1 3 4) #'<)
ERROR:USE-VALUE :R1 Input a value to be used instead of (FDEFINITION 'COMP).
how fix it?
There are quite a few things amiss in your code.
First, in Common Lisp, data and functions live in separate namespaces. For this reason, you cannot use (comp x y) to call the function referred to by the variable comp. You have to use the funcall function.
Second, you are comparing (car seq) with (car seq) - that is, with itself. You probably meant to say (car (cdr seq)), which refers to the second element in the list.
After these changes, the code works correctly:
(defun sorted (seq comp)
(or (< (length seq) 2)
(and (funcall comp (car seq) (car (cdr seq)))
(sorted (cdr seq) comp))))
* (sorted '(1 3 4) #'<)
T
* (sorted '(1 4 3) #'<)
NIL
Evaluating (length seq) on every iteration of your function is not efficient; to get the list's length, the system must go through the entire list. Effectively, your code will spend quadratic time doing a linear operation. It would be better to replace that with a simple end check.
Also, I would use the functions first and second instead of (car seq) and (car (cdr seq)), and rest instead of cdr. It is better to explicitly state in your code what you mean with it.
With these changes, the final code looks like this:
(defun sorted (seq comp)
(or (endp (rest seq))
(and (funcall comp (first seq) (second seq))
(sorted (rest seq) comp))))
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'm new to Scheme (via Racket) and (to a lesser extent) functional programming, and could use some advise on the pros and cons of accumulation via variables vs recursion. For the purposes of this example, I'm trying to calculate a moving average. So, for a list '(1 2 3 4 5), the 3 period moving average would be '(1 2 2 3 4). The idea is that any numbers before the period are not yet part of the calculation, and once we reach the period length in the set, we start averaging the subset of the list according the chosen period.
So, my first attempt looked something like this:
(define (avg lst)
(cond
[(null? lst) '()]
[(/ (apply + lst) (length lst))]))
(define (make-averager period)
(let ([prev '()])
(lambda (i)
(set! prev (cons i prev))
(cond
[(< (length prev) period) i]
[else (avg (take prev period))]))))
(map (make-averager 3) '(1 2 3 4 5))
> '(1 2 2 3 4)
This works. And I like the use of map. It seems composible and open to refactoring. I could see in the future having cousins like:
(map (make-bollinger 5) '(1 2 3 4 5))
(map (make-std-deviation 2) '(1 2 3 4 5))
etc.
But, it's not in the spirit of Scheme (right?) because I'm accumulating with side effects. So I rewrote it to look like this:
(define (moving-average l period)
(let loop ([l l] [acc '()])
(if (null? l)
l
(let* ([acc (cons (car l) acc)]
[next
(cond
[(< (length acc) period) (car acc)]
[else (avg (take acc period))])])
(cons next (loop (cdr l) acc))))))
(moving-average '(1 2 3 4 5) 3)
> '(1 2 2 3 4)
Now, this version is more difficult to grok at first glance. So I have a couple questions:
Is there a more elegant way to express the recursive version using some of the built in iteration constructs of racket (like for/fold)? Is it even tail recursive as written?
Is there any way to write the first version without the use of an accumulator variable?
Is this type of problem part of a larger pattern for which there are accepted best practices, especially in Scheme?
It's a little strange to me that you're starting before the first of the list but stopping sharply at the end of it. That is, you're taking the first element by itself and the first two elements by themselves, but you don't do the same for the last element or the last two elements.
That's somewhat orthogonal to the solution for the problem. I don't think the accumulator is making your life any easier here, and I would write the solution without it:
#lang racket
(require rackunit)
;; given a list of numbers and a period,
;; return a list of the averages of all
;; consecutive sequences of 'period'
;; numbers taken from the list.
(define ((moving-average period) l)
(cond [(< (length l) period) empty]
[else (cons (mean (take l period))
((moving-average period) (rest l)))]))
;; compute the mean of a list of numbers
(define (mean l)
(/ (apply + l) (length l)))
(check-equal? (mean '(4 4 1)) 3)
(check-equal? ((moving-average 3) '(1 3 2 7 6)) '(2 4 5))
Well, as a general rule, you want to separate the manner in which you recurse and/or iterate from the content of the iteration steps. You mention fold in your question, and this points in the right step: you want some form of higher-order function that will handle the list traversal mechanics, and call a function you supply with the values in the window.
I cooked this up in three minutes; it's probably wrong in many ways, but it should give you an idea:
;;;
;;; Traverse a list from left to right and call fn with the "windows"
;;; of the list. fn will be called like this:
;;;
;;; (fn prev cur next accum)
;;;
;;; where cur is the "current" element, prev and next are the
;;; predecessor and successor of cur, and accum either init or the
;;; accumulated result from the preceeding call to fn (like
;;; fold-left).
;;;
;;; The left-edge and right-edge arguments specify the values to use
;;; as the predecessor of the first element of the list and the
;;; successor of the last.
;;;
;;; If the list is empty, returns init.
;;;
(define (windowed-traversal fn left-end right-end init list)
(if (null? list)
init
(windowed-traversal fn
(car list)
right-end
(fn left-end
(car list)
(if (null? (cdr list))
right-end
(second list))
init)
(cdr list))))
(define (moving-average list)
(reverse!
(windowed-traversal (lambda (prev cur next list-accum)
(cons (avg (filter true? (list prev cur next)))
list-accum))
#f
#f
'()
list)))
Alternately, you could define a function that converts a list into n-element windows and then map average over the windows.
(define (partition lst default size)
(define (iter lst len result)
(if (< len 3)
(reverse result)
(iter (rest lst)
(- len 1)
(cons (take lst 3) result))))
(iter (cons default (cons default lst))
(+ (length lst) 2)
empty))
(define (avg lst)
(cond
[(null? lst) 0]
[(/ (apply + lst) (length lst))]))
(map avg (partition (list 1 2 3 4 5) 0 3))
Also notice that the partition function is tail-recursive, so it doesn't eat up stack space -- this is the point of result and the reverse call. I explicitly keep track of the length of the list to avoid either repeatedly calling length (which would lead to O(N^2) runtime) or hacking together a at-least-size-3 function. If you don't care about tail recursion, the following variant of partition should work:
(define (partition lst default size)
(define (iter lst len)
(if (< len 3)
empty
(cons (take lst 3)
(iter (rest lst)
(- len 1)))))
(iter (cons default (cons default lst))
(+ (length lst) 2)))
Final comment - using '() as the default value for an empty list could be dangerous if you don't explicitly check for it. If your numbers are greater than 0, 0 (or -1) would probably work better as a default value - they won't kill whatever code is using the value, but are easy to check for and can't appear as a legitimate average