SU-Ⅲ 電脳紀 Second -2ページ目

SU-Ⅲ 電脳紀 Second

基本的に雑記ですが、情報系の事も書きます。

高校数学でも出てた気がして、
大学生の俺が今更書くのも恥ずかしいけどブログに書いてでも
最近やった内容でこれだけは覚えておきたいと思う。

それと一番下の置き換えをやった時の変形

以上です。
aやbという記号を扱いたいと思ってもこれまで通り
(list a b)
こうやると定義してないとエラーが出ていた。 もしこれをするなら
(list 'a 'b)
とシングルクォートを付け無ければならない。 また
'(a b)
とやっても同じ結果になる。 記号の比較は=ではなくeq?を使う。
リストに関していくつかプログラムをまとめます。
リストをまず
(define l1 (list 0 1 2 3 4 5 6 7 8 9))
と定義します。
次の関数を作る。 「リストを引数に取り、そのリストの要素を逆順に入れているリストを返す」 反復的なプロセスによる再帰で作れる。
(define my-reverse  (lambda (l)
    (define inner
      (lambda (l n)
        (if (null? l)
            n
            (inner (cdr l) (cons (car l) n))
         )
        )
      )
    (inner l '())
    )
  )

「述語とリストを受け取り、述語が真である要素の数を数える関数」 前回のmy-filterと似ているが、今回は数を数えるだけで良い。
(define my-counter  (lambda (condition l)
    (define inner
        (lambda (condition l n)
          (cond 
            ((null? l) n)
            ((condition (car l)) (inner condition (cdr l) (+ n 1)))
            (else (inner condition (cdr l) n))
            )
         )
      )
    (inner condition l 0)
     )
  )



「引数としてリスト(全て数値で構成)を受け取り、その3乗和を計算する関数」

考え方としてはまず(1)受け取ったリストの各要素を3乗した新たなリストを作成し、(2)リストの各要素を足し合わせるというのが手っ取り早いと思われる。
組み込みのmapとreduceを使うと便利。
だがここでは敢えてその二つから作る。

(1)各要素に何か計算を施した新たなリストを返すmy-mapの作成
詳しくは高階関数に関する記事を参照。
(define my-map
  (lambda (process l)
    (if (null? l)
        '()
        (cons (process (car l)) (my-map process (cdr l)))
        )
    )
  )
(2)与えられたリストの各要素のcarとcdrに対して再帰的に演算を行う。 (関数 (リストcar1) (関数 (リストcar2) (関数 (リストcar3)...))) 関数は2つの値を引数に持つものである必要がある。 この関数に当たる部分を+に変えれば再帰的プロセスで総和を求めることも可能。
(define my-reduce  (lambda (process initial l)
    (if (null? l)
        initial;これは総和を求める際は0、積の場合は1といった具合
        (process (car l) (my-reduce process initial (cdr l)))
     )
    )
  )
総和なら次の1行目、リストが連続した自然数なら階乗を求めたりもできる。
(my-reduce + 0 l1)
(my-reduce * 1 (list 1 2 3 4))
これらの関数を組み合わせたら瞬殺。
(define sum-of-pow3  (lambda (l)
    (my-reduce + 0 (my-map (lambda (x) (* x x x)) l))
    )
  )
lambdaの書き方に慣れていればこういうときにいちいち外部に2乗するための関数を書かなくてもよくなったりする良いことがあります。 敢えてmapやreduceを自作しましたが組み込みで使えるはずなのでそっちでやったほうが速く終わります。ただ自分としても内部の確認をもう一度したかったのでわざとなるべく自作という方針でやりました。
昨日今日で記事書きまくってます。 昨晩は最後と思われる課題を終わらせ春休みに突入することができました。 来年度は真剣にやらなければならない年なので予め春休みの目標を立てておきます。
  • 数学の本4冊は最低でも読破する(微積・線形・フー・常微)
  • ↑の間を極力英語の勉強で埋める
  • 来年度の学生祭のWEBアプリのベースを作成する
  • 「今夜のCLANNAD英語」のコーナーを進める
  • 授業で習ったSchemeの俺流まとめを一通りやる
あまり立てすぎると挫折しそうなのでとりあえずこのくらいにしておきます。 つい先日、DS版の「英語漬け」をハンココンプで終わらせました。 そして今は3DSのTOEICのやつに手を付けてるんですがムズイっすね。 でも個人的に英語はTOEICで良い点取るよりアニメの吹き替え版を見るための道具的なポジションなのでとりあえず耳に入って日本語に頑張って変換しなくても無意識に何言ってるか分かるレベルまではいきたいです。もちろん文法もやりますが。 何度かCLANNADも観ているのですが最近新しく北米版の円盤が欲しいと思ってます。候補としては「A CERTAIN SCIENTIFIC RAILGUN」か「PUELLA MAGI MADOKA☆MAGICA」なのですが、前者はそもそもBD版が無い(?)、後者はBD版あるけど導入コストが馬鹿にならない(1枚7000円オーバー換算*3巻(だったと思う))。 まあファンの方たちからしたらお前それでもファンのつもりか!ってとこでしょうけどね……(-_-;)
実はあるよとか何か情報をお持ちの方は教えていただけると嬉しいです。

ということで春休み頑張りましょう!
高階関数とは…関数を引数として受け取る関数 めちゃくちゃ簡単な例作ってみた↓
(define pow2
  (lambda (x)
    (* x x)
    )
  )
(define eval-func
  (lambda (f x)
    (f x)
    )
  )
eval-funcというのが高階関数で、他のpow2は次の呼び出しで使います。 高階関数eval-funcは引数としてfとxを受け、(f x)の結果を返します。 fは括弧で囲まれた一番左なので関数である必要があります。 そしてさらに言うとこの括弧の一番左以外にはxの1つしかないので 引数を1つ持つある関数をfにしなければなりません。 なので引数を一つ受け取って2乗や4乗を返す関数を作りました。 次の呼び出しはどちらも一緒の値を返します。
(eval-func pow2 5)
(eval-func (lambda (x) (* x x)) 5)
1行目は1つの引数を受けてその引数を2乗するpos2をeval-funcのfに与えています。 2行目はlambdaで即席で作った関数を与えています。どちらも一緒です。

ペア…2つ要素を持つもの
リスト…ペアをつなげて作れる

ペア…consを使って作れる。
(define p (cons 1 2))

こうすると、

ペア

上の図のpのほうのようになります。 list関数を使っても似たようなことができますが、形が少し変わります。
(define p2 (list 1 2))

この場合は図のp2のほうのようにペアを二つつかってそれらを連結した形で1と2が格納されます。 まあ関数名がlistだけあってリストを作ることを前提にこうなってるんですが。 なのでcdrを取り出すとそれぞれ違った結果が返ってきます。 car関数…ペアの1番目の要素を取り出す。 cdr関数…ペアの2番目の要素を取り出す。 pのcdr要素は原始的な2という数字、p2は2番目の要素を持たないペアが出てきます。 p2で2を取ろうと思えば
(car (cdr p2))

とか
(cadr p2))

とする必要があります(2個めの省略記法はある程度までなら定義されてるけど長いと読み返すとき訳わかめになるので1個めのほうが良いかも)。 list関数でやってることは
(cons 1 (cons 2 '()))

と同じ。 '()はnullのようなもの。
で、最初の高階関数とリストの連携技みたいなこともできるので両者は共に便利ですよね。みたいな。 さっきのp2を1から7までの奇数に変えます。 また引数lで受け取ったリストのcar要素をprocess関数で評価した結果に変えたリストを返す高階関数my-mapを作ります。
(define my-map
  (lambda (process l)
    (if (null? l)
        '()
        (cons (process (car l)) (my-map process (cdr l)))
        )
    )
  )
cons関数でペアを作る時そのcar要素をlのcar要素をprocessで評価したしたものにします。またcdr要素については自信にlの残りを与えて呼び出すことでリストを形成します。 次で呼び出します。
p2(my-map (lambda (x) (* x 3)) p2)
my-map関数の呼び出し部分はp2の各値が3倍になったリストが返ってきていることが確認できるはずです。 当然ですが関数の実行前後でp2の値は変わりません。consで新たにペアを作って全く新しいリストが作られるからです。なのでこの値を今後何度も使う場合は次のようにdefineしとけば便利かもしれません。
(define p3 (my-map (lambda (x) (* x 3)) p2))

mapを少し応用して条件にマッチした要素のみで構成された新たなリストを作る関数my-filterも自作できます。今回は高階関数の引数processには述語を与えます。 あえてifのネストで書きました。
(define my-filter  (lambda (process l)
    (if (null? l)
        '()
        (if (process (car l))
            (cons (car l) (my-filter process (cdr l)))
            (my-filter process (cdr l))
            )
        )
    )
  )
例えば次のように実行すると5以上の要素だけで作られた新たなリストを返します。
(my-filter (lambda (x) (<= 5 x)) p2)
もっともmapやfilterなどの関数はもともとあるのでわざわざ作る必要も無いのですが。