Hjälp med Lisp(Scheme dialekten)

Permalänk
Medlem

Hjälp med Lisp(Scheme dialekten)

Hur can jag skriva om denna rekrusiva funktionen:

define (make-list x y) (if (zero? y) '() (cons x (make-list (+ x 1) (- y 1)))))

Min Scheme implementation har problem med denna funktion av nån anledning(eller är funktionen i sig fel?). Så jag skulle vilja skriva om den med hjälp av lambda och denna funktionen istället:

(define (foldl func accum lst) (if (null? lst) accum (foldl func (func accum (car lst)) (cdr lst))))

Skulle detta vara möjligt? Också skulle jag vilja skriva en fibonacci funktion som i ett mer orekrusivt sätt(alltså den använder foldl för att loopa och är inte själv rekrusiv)?

Visa signatur

Nybörjar guide: Xonotic 1on1 | FX-4100 Black Edition X4 @ 3,6GHz, MSI GTX650 1GB OC, Crossair VENGEANCE 8GB @ 1600 MHz, och lite annat skrot ;)

Permalänk
Medlem
Skrivet av klr:

Hur can jag skriva om denna rekrusiva funktionen:

define (make-list x y) (if (zero? y) '() (cons x (make-list (+ x 1) (- y 1)))))

Min Scheme implementation har problem med denna funktion av nån anledning(eller är funktionen i sig fel?).

Har du glömt en ( i början? Eller har du bara kopierat fel. För med en parentes där så funkar koden.

Skrivet av klr:

Så jag skulle vilja skriva om den med hjälp av lambda och denna funktionen istället:

(define (foldl func accum lst) (if (null? lst) accum (foldl func (func accum (car lst)) (cdr lst))))

Skulle detta vara möjligt?

Fold viker ihop en lista till en (oftast) mindre sak. make-list gör motsatsen, så du borde inte använda fold för att implementra make-list.

Skrivet av klr:

Också skulle jag vilja skriva en fibonacci funktion som i ett mer orekrusivt sätt(alltså den använder foldl för att loopa och är inte själv rekrusiv)?

Lär dig skriva!

Permalänk
Medlem

Jag föreslår du löser Fibonacci med en oändlig ström (tas upp i SICP boken http://mitpress.mit.edu/sicp/full-text/sicp/book/node69.html)

Först behöver vi definera hur strömmar funkar:

;; Se SICP boken http://mitpress.mit.edu/sicp/full-text/sicp/book/node70.html ;; Den här koden fungerar med Scheme dialekten Racket. (define-macro cons-stream (lambda (a b) `(cons ,a (delay ,b)))) (define stream-null? null?) (define stream-car car) (define (stream-cdr stream) (force (cdr stream)))

Efter det kan vi skapa vår Fibonacci serie:

;; Definition av fibonacci ;; http://mitpress.mit.edu/sicp/full-text/sicp/book/node71.html (define (fibgen a b) (cons-stream a (fibgen b (+ a b)))) (define fibs (fibgen 0 1))

Du får första elementen i den oändliga listan genom (stream-car fibs), och andra elementet med (stream-car (stream-cdr fibs)) osv. precis som en vanlig lista.

Här är en liten hjälpfunktion för att skriva ut N st element ur en ström S.

;; Hjälp sak för att skriva ut. (define print-stream ;; This obscure definition saves a lot of cons cells during ;; garbage collection! (let () (define (iter s n) (cond ((stream-null? s) (display "]")) ((zero? n) (display "... ]")) (else (begin (display (stream-car s)) (display " ") (iter (stream-cdr s) (- n 1)))))) (lambda (s n) (display "[ ") (iter s n) (newline))))

Resultatet av de 20 första talen blir:

> (print-stream fibs 20) [ 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 ... ]

Fördelen med denna typ av strömmar är att beräkningen för nästa element fördröjs tills stream-cdr är körs, vilket gör att du kan definera strömmen och sedan hämta nästa element i all evighet sedan fibonacci serien inte har ett slut.

För make-list så tror jag du vill använda foldr så listan blir åt rätt håll:

> (foldr cons '() '(1 2 3 4)) (1 2 3 4)

Men du vinner egentligen inget på det.

Du kan istället definera en högre ordningens funktion för att ackumulera värden i en lista.
Du kan t.ex. definera en ackumulator såhär (kanske lite att ta i dock):

(define (accumulate combiner null-value term a next b) (if (> a b) null-value (combiner (term a) (accumulate combiner null-value term (next a) next b))))

Med den funktionen kan vi sedan definera om make-list såhär:

;; Lite hjälpfunktioner som används av make-list (define (self-echo x) x) (define (next x) (+ x 1)) (define (end-term x y) (- (+ x y) 1)) ;; accumulate slutar när a > b, alltså x >= x+y (define (make-list x y) (accumulate cons '() self-echo x next (end-term x y)))

Du kan använda accumulate till samma saker som du använder foldl och foldr också. T.ex. summera varannat tal mellan 1 och 9:

(accumulate + 0 (lambda (x) x) 1 (lambda (x) (+ x 2)) 9)

Högre ordningens funktioner är väldigt kraftfulla.

Permalänk
Medlem

@lz. Tack för svaret! Min implemntation har inte support för macros, dock så har jag länge väntat på ett konkret exempel hur man använder dem, så stort tack!

@tufflax Jag pasta fel, och jag inser nu att det var dumbt att försöka anvönda fold. Jag ska också lära mig skriva, vanare vid engelska :P`btw är du med i Got.clj?

Jag antar att ne bättre lösning är att använda unfold

Visa signatur

Nybörjar guide: Xonotic 1on1 | FX-4100 Black Edition X4 @ 3,6GHz, MSI GTX650 1GB OC, Crossair VENGEANCE 8GB @ 1600 MHz, och lite annat skrot ;)

Permalänk
Medlem
Skrivet av klr:

@lz. Tack för svaret! Min implemntation har inte support för macros, dock så har jag länge väntat på ett konkret exempel hur man använder dem, så stort tack!

@tufflax Jag pasta fel, och jag inser nu att det var dumbt att försöka anvönda fold. Jag ska också lära mig skriva, vanare vid engelska :P`btw är du med i Got.clj?

Jag antar att ne bättre lösning är att använda unfold

Är Got.clj nån grupp i Göteborg? Är inte med iaf.