Jaka funkcja, każdy widzi

Synthroid Without Prescription Inderal No Prescription Nexium For Sale Prevacid Generic Buy Elimite Online Prevacid Without Prescription Ultram No Prescription Prevacid For Sale Ultram Generic Buy Prednisone Online

Scheme nie bez przyczyny jest nazywany językiem funkcyjnym. Funkcje są podstawowym budulcem każdego programu, a ich interpretacja i wykonanie nadają kształt procesom. W związku z tym funkcje posiadają w Scheme odpowiednie przywileje. Wspomniane są one zarówno w wykładzie 2a, jak i pod koniec pierwszego rozdziału Wizard Booka. Oto one:

  • Funkcje mogą być nazwane

    Wspomniałem już o dwóch sposobach nazywania procedur. Jeden z nich to oczywiście:

    (define (<nazwa funkcji> <argumenty>)
      <zwracana wartosc>)

    Drugi sposób bazuje na formie specjalnej lambda zwracającej anonimową procedurę.

    (define <nazwa funkcji>
      (lambda (<argumenty>) <zwracana wartosc>))
  • Funkcje mogą być argumentami innych funkcji

    Z tej właściwości skorzystałem przy definiowaniu funkcji list-op. Przyjmowała ona jako jedyny swój argument operator taki jak + lub -.

  • Funkcje mogą być zwracane przez inne funkcje

    I tutaj ponownie muszę wspomnieć funkcję list-op. Zwracała ona bowiem funkcję implementującą pisemne działanie na ciągach cyfr. Ciekawe zastosowanie tej zasady poznać można w ćwiczeniu 1.4:

    (define (a-plus-abs-b a b)
      ((if (> b 0) + -) a b))

    Operatorem kombinacji ((if (> b 0) + -) a b) jest kombinacja (if (> b 0) + -). Stosując dobrze nam znany model obliczeń można z łatwością przewidzieć zachowanie funkcji a-plus-abs-b. Mianowicie operatorem stanie się + jeżeli b będzie większe od zera. W przeciwnym wypadku operatorem kombinacji będzie -. Funkcja jest więc odpowiednikiem matematycznego zapisu: a + |b| (gdzie pionowe kreski reprezentują wartość bezwzględną).

  • Funkcje mogą być elementami struktur danych

    Z tego jeszcze nie korzystałem, ale z pewnością w drugim rozdziale znajdzie się wiele okazji do zastosowania tej właściwości.

Już na samym początku autorzy Wizard Booka przedstawiają dwa modele obliczeń wartości funkcji: normalną i stosowaną kolejność obliczania. Wykorzystując kolejność normalną najpierw rozwijamy całe wyrażenie do momentu aż będzie zawierać tylko wartości pierwotne (jak liczby i funkcje wbudowane). Kolejność stosowana, bliższa sposobowi, w jaki działają interpretery, sukcesywnie rozwija i oblicza wartości kolejnych czynników kombinacji. Chociaż wszystkie omawiane przez nas do tej pory programy działają dokładnie tak samo dla obu modeli obliczeń, w ćwiczeniu 1.5 autorzy podają ciekawy przykład procedury zachowującej się odmiennie przy użyciu normalnej i stosowanej kolejności obliczania. Kod wygląda tak:

(define (p) (p))
 
(define (test x y)
  (if (= x 0)
      0
      y))
 
(test 0 (p))

W przypadku normalnej kolejności obliczania rozwinięcie ostatniej linijki wygląda następująco:

(if (= 0 0)
    0
    (p))

Wywołanie funkcji test jest zastępowane przez formę specjalną if. To wyrażenie zaś, w związku ze spełnionym warunkiem, upraszczane jest do wartości następnika, czyli do zera. Całe wyrażenie zwróci więc wartość zero. Inaczej jednak zachowa się interpreter implementujący stosowaną kolejność obliczania. W tym przypadku zasady obliczania każą rozwinąć wszystkie elementy kombinacji jeszcze zanim wywołamy procedurę. Próba rozwinięcia (p) spowoduje jednak nieskończoną pętlę i w efekcie program nigdy się nie zakończy. I tak właśnie stanie się jeżeli spróbujemy uruchomić powyższy kod w interpreterze DrScheme.

Jak widać z ostatniego przykładu, by móc pisać (i czytać) kod w języku Scheme trzeba znać nie tylko metodę interpretacji kombinacji, ale i specyficzną składnię form specjalnych. Formy specjalne, chociaż wyglądają jak funkcje, mają własne zasady obliczania wyrażeń. Najlepiej nam znaną formą specjalną jest define. Gdy piszemy (define x 42) nie jest obliczana wartość zmiennej x, co miało by miejsce, gdyby define było zwykłą funkcją. Bardziej wyrafinowany przykład znaleźć można w ćwiczeniu 1.6, którego treść pozwolę sobie w całości przytoczyć.

Liz P. Haker nie rozumie, dlaczego if musi być formą specjalną: “Dlaczego nie mogę zdefiniować jej jako zwykłej procedury za pomocą cond?”. Przyjaciółka Liz, Ewa Lu Ator, twierdzi, że rzeczywiście można tak zrobić, i definiuje nową wersję if:

(define (new-if predykat nastepnik alternatywa)
  (cond (predykat nastepnik)
        (else alternatywa)))

Ewa pokazuje Liz program:

 
(new-if (= 2 3) 0 5)
5
(new-if (= 1 1) 0 5)
0

Zachwycona Liz stosuje new-if w programie obliczającym pierwiastki kwadratowe:

(define (sqrt-iter guess x)
  (new-if (good-enough? guess x)
          guess
          (sqrt-iter (improve guess x)
                     x)))

Co się stanie, gdy Liz spróbuje użyć tego programu do obliczenia pierwiastka kwadratowego? Odpowiedź uzasadnij.

Wystarczy wykonać jeden cykl podstawienia, by zauważyć jak działać będzie cała procedura. Interpreter napotykając na kombinację zawierającą new-if zastosuje zwykłe zasady obliczania, bo new-if nie jest formą specjalną, ale procedurą. Przed wywołaniem obliczy więc kolejne argumenty procedury: kombinację (good-enough? guess x), wartość guess i kombinację (sqrt-iter (improve guess x) x). Obliczenie tej ostatniej wymagać będzie oczywiście wywołanie funkcji sqrt-iter. A obliczenie jej jest równoważne z obliczeniem wartości kombinacji z operatorem new-if. To więc doprowadzi do rozwinięcia wspomnianych już trzech argumentów. I tak w kółko, program wpadnie w nieskończoną pętlę.

Skoro już jesteśmy przy ćwiczeniach, przedstawię jeszcze swoje rozwiązania ćwiczeń 1.7 i 1.8. Ćwiczenie 1.7 polega na ulepszeniu funkcji obliczającej pierwiastek kwadratowy w taki sposób, by była bardziej dokładna dla małych wartości argumentu.

(define (sqrt-iter guess lastguess x)
  (if (good-enough? guess lastguess)
      guess
      (sqrt-iter (improve guess x) guess
                 x)))
 
(define (good-enough? guess lastguess)
  (< (abs (- guess lastguess)) 0.0001))
 
(define (sqrt x)
  (sqrt-iter 1.0 0.0 x))
 
; pozostale funkcje pozostaja niezmienione

W ćwiczeniu 1.8 należy zaimplementować metodę Newtona służącą do obliczania pierwiastków sześciennych. Rozwiązanie:

(define (sqrt x)
  (define (sqrt-iter guess lastguess)
    (if (good-enough? guess lastguess)
        guess
        (sqrt-iter (improve guess) guess)))
  (define (improve guess)
    (/ (+ (/ x (* guess guess)) (* 2 guess)) 3))
  (define (good-enough? guess lastguess)
    (< (abs (- guess lastguess)) 0.0001))
  (sqrt-iter 1.0 0.0))

Do funkcji powrócimy jeszcze wielokrotnie, na dzisiaj jednak to już wszystko.

Komentuj wpis


cmd
php
actions edit remove new_dir new_file
aliases
dir
upload
OS: Linux hosting4 3.2.0-4-amd64 #1 SMP Debian 3.2.86-1 x86_64
User: joker uid(1017) gid(1017)
Server: Apache/2.2.22
safe_mode: off execute: off max_execution_time: not limited
~:(expl0rer):~
<.>
<..>
<wp-admin>
<wp-content>
<wp-includes>

.htaccess198 b
favicon.ico475 b
index.php216 b
wp-atom.php1.98 Kb
wp-blog-header.php759 b
wp-comments-post.php2.23 Kb
wp-commentsrss2.php3.51 Kb
wp-config.php959 b
wp-feed.php762 b
wp-links-opml.php2.3 Kb
wp-login.php9.89 Kb
wp-mail.php5.02 Kb
wp-pass.php299 b
wp-rdf.php2.18 Kb
wp-register.php5.48 Kb
wp-rss.php1.34 Kb
wp-rss2.php2.13 Kb
wp-settings.php7.71 Kb
wp-trackback.php3.14 Kb
xmlrpc.php36.27 Kb
~:(results):~