SICPを読む(37) 問題 2.4 consの別の表現。

問題2.4

consの別の表現。何故xを返すことが出来るのか。

(define (cons x y)
  (lambda (m) (m x y)))
(define (car z)
  (z (lambda (p q) p)))

(cons 1 2)
(car (cons 1 2)) ; 1

展開してみよう。

(car (cons 1 2))
; (cons 1 2)を(cons x y)で展開。
(car (lambda (m) (m 1 2)))
; carを展開。
((lambda (m) (m 1 2)) (lambda (p q) p))
; mに代入する。
((lambda (p q) p) 1 2)
; (p q)に1 2を代入するとpを返すから、
1 


でた。zの所が逆になるのでややこしい。

一番のポイントは最初の展開、x yは1 2で束縛されてる。

cdrは簡単。

(define (cdr z)
  (z (lambda (p q) q)))

直感的に捉えるのはちょっとムズい。

今日のSchemeリンク

なんでもλ

以前覗いたときはさっぱり意味不明だったけど、理解できる!!

成長したな僕。

しかし・・・。

Schemeにおける「関数」はより抽象的な処理ブロックを記述するのに使われ、 C言語における「関数」とは一対一に対応しない。

言い替えると、C言語の関数はポインタで、Schemeの関数はオブジェクトだって事だ!!

orz。

もう一個

Karetta|Schemeの評価モデルとは?
最後の方の環境フレームの説明がわかりやすい。

完璧に理解できた(ようなきがする)

次の2問が難問なんですが・・・。

K&Rを読もう(3) 1.5(1) catを作ろう。再帰と関数のネストのテストも兼ねて。

またまた定番。catを作ろうのコーナー。

定番過ぎるので、再帰と関数のネストを使ってみました。

バリバリgccオンリーのCコードデス。

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int (*f)(int) = putchar;
    
    void read_char(void)
    {
        int c;
        if ((c = getchar()) != EOF) {
            f(c);
            return read_char();
        } else
            return;
    }

    read_char();
    exit(EXIT_SUCCESS);
}

コンパイルとテスト。

% gcc -Wextra -O2 -o cat 1.5.1.c
% ./cat
Hello, K&R cat world!!
Hello, K&R cat world!!

スコープの確認も出来ました。

ま、普通のcatですね・・・。

演習 1-6

括弧を除くと、111...最後が0であることが確認できた。よく忘れるので注意したい。

演習 1-7

EOFを印字せよ。

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int (*middle_f)(int);
    int (*end_f)(int);

    void read_char(void)
    {
        int c;
        if ((c = getchar()) != EOF) {
            middle_f(c);
            return read_char();
        } else {
            end_f(c);
            return;
        }
    }

    int print_eof(int c)
    {
        return printf("EOF -- getchar returned %d --\n", c);
    }

    middle_f = putchar;
    end_f = print_eof;

    read_char();
    exit(EXIT_SUCCESS);
}

middle_f,end_fを定義した。

% gcc -Wextra -O2 -o cat ex-1-7.c
% ./cat
test
test
EOF -- getchar returned -1 --

EOFが-1であることも確認できた。詳しくは、man readcharか、/usr/include/stdio.h

/* End of file character.
   Some things throughout the library rely on this being -1.  */
#ifndef EOF
# define EOF (-1)
#endif

(-1)となってる理由がイマイチ不明。