Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
ヤドカリデンキ商会(第一倉庫)
[go: Go Back, main page]

Hatena::Diary

ヤドカリデンキ商会(第一倉庫)

2009-06-24

[]第159回 素人くさいSICP読書会(at 月島某所)

  • 会場提供&お菓子ありがとうございました
  • おみやげはいつものように杏仁豆腐。ご家族には「杏仁豆腐のお兄ちゃんたち」という評価が定着しているもよう
  • かっくんが買ったばかりのMacBook Proを持ってきてた。そこからMacの話題。Quicksilverのメモリ消費量がひどい、とか
  • 佐野さんのノキア端末は圏外になるとリセットがかかるらしい。ひどい話
  • 結局、この日は問題5.3に終始
  • 問題5.3
  • 書く必要があるのは図が二つとコード(制御器の定義)が二つ
  • hisaさんから「コードから書いた方がやりやすい」と聞いたので、問題とは逆にコードから書く
  • good-enough?とimproveを基本演算としてまず書き、それらの中身をちまちまバラしていく。面倒だけど機械的な作業なので難しくはない。人力コンパイラ
  • 元のSchemeのコードの内部defineではxは引数として取っていないが、xを捕捉して中で利用しているので、good-enough?とimproveはxを取るように記述した
  • hisaさんと答合わせしたらほぼ同じだった
  • 杉本さんに「全体のループを忘れている」と指摘された。たしかにループがないと使い捨てで二度と使えなくなってしまう
  • で、こんな感じ

good-enough?とimproveが基本演算の場合

(controller
 sqrt-loop
   (assign x (op read))
   (assign guess (const 1.0))
 good-enough-test
   (test (op good-enough?) (reg x) (reg guess))
   (branch (label sqrt-done))
   (assign guess (op improve) (reg x) (reg guess))
   (goto (label good-enough-test))
 sqrt-done
   (perform (op print) (reg guess))
   (goto (label sqrt-loop)))

算術演算のみに展開

(controller
 sqrt-loop
   (assign x (op read))
   (assign guess (const 1.0))
 good-enough-test
   (assign t (op *) (reg guess) (reg guess))
   (assign t (op -) (reg t) (reg x))
   (test (op >) (reg t) (const 0))
   (branch (label abs-done))
   (assign t (op *) (reg t) (const -1))
 abs-done
   (test (op <) (reg t) (const 0.001))
   (branch (label sqr-done))
   (assign t (op /) (reg x) (reg guess))
   (assign t (op +) (reg t) (reg guess))
   (assign guess (op /) (reg t) (const 2))
   (goto (label good-enough-test))
 sqrt-done
   (perform (op print) (reg guess))
   (goto (label sqrt-loop)))

手持ちの紙に殴り書きした図(汚いなー)

f:id:yad-EL:20090625073455j:image

  • この図をhisaさんがOmniGraffleで書こうとして悪戦苦闘してた
  • 複雑な方の図は面倒なのでパス。一時変数を1個所にまとめると線がぐしゃぐしゃになるはずなので「エイリアスにすればいんじゃね」と提案。「回路図GNDみたいな感じ」(佐野さん)
  • 次回は問題5.3の答をプロジェクタで確認して、次の本文に入る予定

2009-06-20

Scheme初心者へのアドバイスを書いてみる

id:tsuyoshikawaさんが初めてSchemeのコードを書いた(ここにあるコード)と聞いて「初めてでここまで書けるのはすげー」と思いました。ということで、このコードについて私ができる範囲でアドバイスしてみます。私自身はSchemeプログラマのレベル10でレベル3〜4程度のへっぽこSchemerなのですが。

閉じカッコの位置について

コーディング・スタイルは典型的な「自転車置き場の議論」なのでそれほど気にする必要はないと思いますが、一応、触れておきます。

tsuyoshikawaさんは

(define (size-of lis)
  (if (null? lis)
      0
      (+ 1 (size-of (cdr lis)))
      )
  )

のように書いているのですが、実際には

(define (size-of lis)
  (if (null? lis)
      0
      (+ 1 (size-of (cdr lis)))))

のように閉じカッコは最後にまとめて書くことが多いです。Lisperのコードブロックの認識は、実はPythonistaに近いんじゃないかなと思っています。Schemeコーディングスタイルについてはここを参考に。

標準関数について

tsuyoshikawaさんが自作している関数は、実際には標準で用意されているものが多かったりします。練習の意味で自作しているのだと思うのですが、同様の関数が用意されているかどうかを調べてみました。

【R5RSで規定されている関数

R5RSはSchemeの言語仕様です。最新の仕様はR6RSですが、まだ対応しているものはそれほど多くないようなので、とりあえずSchemeの標準が知りたかったらR5RSに当たるのがよいと思います。

  • リストにある要素が含まれるか:memberもしくはmemq
  • リストのサイズを測る:length
  • n番目の要素を取り出す:list-ref
  • リストにリストを付け加える:append
  • 2番目の要素を取り出す:cadr

といったものはR5RSに準拠した処理系では標準で利用できます。

SRFI-1で規定されている関数

Schemeには、言語仕様と切り離された形でSRFIというライブラリ仕様群があります。その一つであるSRFI-1にはリスト操作関連の関数がまとめられています。SRFI-1の中に「二つのリストの積集合を返す」機能を持つ「lset-intersection」という関数がありました。ただ、この関数を試しに使ってみたところ、速度的なペナルティがかなりありました。今回の例では、自作する方がいいみたいです。このあたりの判断は難しいなと思いました。

末尾再帰について

先ほどの

(define (size-of lis)
  (if (null? lis)
      0
      (+ 1 (size-of (cdr lis)))))

なのですが、Schemerならたいてい

(define (size-of lis)
  (define (size-of-iter a count)
    (if (null? a)
      count
      (size-of-iter (cdr a) (+ 1 count))))
  (size-of-iter lis 0))

のように本能的に書き換えます(このコード自体はSICP日本語版の23ページにそのまま載っています)。このように再帰する部分が関数の呼び出しそのものになっている形を末尾再帰といいます。Schemeの言語仕様では、処理系は末尾再帰をgotoと等価になるよう最適化しなければならないと定められています。つまり、末尾再帰の形にするとスタック消費や速度の面で有利なので、Scheme再帰では末尾再帰を多用します。

ifのネストについて

(define (flatten lis)
  (if (null? lis)
      '()
      (if (pair? lis)
          (my-append (flatten (car lis)) (flatten (cdr lis)))
          (list lis)
          )
      )
  )

は自分なら

(define (flatten lst)
  (cond ((null? lst) '())
        ((symbol? lst) (list lst))
        (else (append (flatten (car lst)) (flatten (cdr lst))))))

と書くかな、と思いました。ifのネストが必要な場合ももちろんありますが、条件が並列に存在する場合はcondをよく使います。こんな風に書くと、(null? lst)がcdrで潜っていったときの終了条件で、(symbol? lst)がcarで潜っていったときの終了条件だということが一目でわかると思います。

ちなみに条件が一つだけの場合でもcondを使う人もいます。Schemeで複数の処理を順番に行うには普通はbeginを使いますが、condのelse節の中ではbeginを使わなくても複数の処理を記述できるためです。

(ここからは余談)

先ほど「再帰はなるべく末尾再帰にする」と書いたのですが、このflattenのような形の再帰は一時変数を導入するだけでは末尾再帰にはできません。末尾再帰にしたければ「継続渡しスタイル(CPS)」を使います。

(define (flatten lst) 
  (define (flatten/cps lst cont)
    (cond ((null? lst) (cont '()))
          ((symbol? lst) (cont (list lst)))
          (else
           (flatten/cps
            (car lst)
            (lambda (f)
              (flatten/cps
               (cdr lst)
               (lambda (r) (cont (append f r)))))))))
  (flatten/cps lst values))

lambdaを使って継続を明示的に自作して再帰の際に渡しています。これにより末尾再帰を実現できています。ただし、この場合はこのように無理矢理末尾再帰にしてもあまりうれしくありません。継続が大量にできてしまうので、結局、末尾再帰にしない場合と同じようにスタックを消費してしまいます スタックは消費しませんがlambdaの分、リソースを消費してしまいます。このあたりに興味があればなんでも継続を読むとおもしろいと思います。

ということでコード全体をオレオレリファクタリング

グローバルの即値をなるべく排除するよう整理してみました。基本的なロジックは変えてないです

(use srfi-1)
(use srfi-27)
(use util.list)

;;乱数の初期化
(random-source-randomize! default-random-source)

;;二つのリストの積集合を返す
(define (intersection lst1 lst2)
  (define (iter lst1 lst2 result)
    (if (null? lst1) result
        (if (memq (car lst1) lst2)
            (iter (cdr lst1) lst2 (cons (car lst1) result))
            (iter (cdr lst1) lst2 result))))
  (iter lst1 lst2 '()))

;;ボードの生成
(define (make-board n)
  (iota (* n n) 1))

;;勝利パターンの生成
(define (make-win-patterns n)
  (define (verticalize m)
    (if (null? (car m)) '()
        (cons (map car m) (verticalize (map cdr m)))))
  (let ((horizontal-patterns (slices (make-board n) n)))
    (cons (iota n 1 (+ n 1))
          (cons (iota n n (- n 1))
                (append horizontal-patterns
                        (verticalize horizontal-patterns))))))

;;プレーヤのコンストラクタ
(define (make-player name)
  (cons name '()))

;;プレーヤのセレクタ
(define (name player)
  (car player))

(define (pieces player)
  (cdr player))

;;勝利判定
(define (win? pieces n win-patterns)
  (if (null? win-patterns) #f
      (if (eq? n
               (length (intersection pieces (car win-patterns))))
          #t
          (win? pieces n (cdr win-patterns)))))

;;盤から一つ番号を選ぶ
(define (choice player board)
  (let ((rnd (random-integer (length board))))
    (values
     (cons (name player) (cons (list-ref board rnd) (pieces player)))
     (append (take board rnd) (cdr (drop board rnd))))))
 
;;決着するまで回数を重ねる
(define (fight name1 name2 n)
  (define (loop player-a player-b board win-patterns)
    (if (null? board)
        (cond [(win? (pieces player-a) n win-patterns) (name player-a)]
              [(win? (pieces player-b) n win-patterns) (name player-b)]
              [else 'draw])
        (receive (pl bo) (choice player-a board)
          (if (win? (pieces pl) n win-patterns)
              (name player-a)
              (loop player-b pl bo win-patterns)))))
  (loop (make-player name1)
        (make-player name2)
        (make-board n)
        (make-win-patterns n)))

;;指定回数ゲーム実行
(define (run name1 name2 n max)
  (define (loop c1 c2 cd)
    (if (eq? (+ c1 c2 cd) max)
        (print name1 ":" c1 " " name2 ":" c2 " draw:" cd)
        (let ((result (fight name1 name2 n)))
          (cond ((eq? result name1) (loop (+ c1 1) c2 cd))
                ((eq? result name2) (loop c1 (+ c2 1) cd))
                (else (loop c1 c2 (+ cd 1)))))))
  (loop 0 0 0))

;;実行
(run 'P1 'P2 3 10000)

ささだささだ 2009/06/22 08:59 このCPSではスタックは消費しないんじゃないでしょうか.

zickzick 2009/06/22 12:28 > 末尾再帰にしない場合と同じようにスタックを消費してしまいます
この場合、スタックじゃなくてヒープを使用しそうな気がします。

yad-ELyad-EL 2009/06/22 14:19 お二人ともサンクスです。shiroさんのとこに「スタックは消費しない」って書いてありますね。失礼しました

2009-06-17

[]第158回 素人くさいSICP読書会(at 三田某所)

  • 会場提供ありがとうございました
  • 一応、問題5.2のあとから問題5.3の前までを音読
  • 「働き」って???
  • 「働き(action)」との表記で、アクションのことだと判明
  • 造り酒屋では杜氏の下で働く人のことを「働き」と呼ぶという話から、本文の「ボタンを押すと働きが起きる」がモダンタイムズじゃね?とか
  • rem、read、printは演算、このうち効果を持っているprintはアクション
  • Haskellのactionっぽい感じかな
  • 作用と副作用って何が違うの、とか
  • remainderとreminder
  • hisaさんがoptical diskと言ってもネイティブに通じなかった話
  • 次回は問題5.3の答合わせから

2009-06-15

Shibuya.lisp テクニカルトーク#3について

イベントの告知へのリンク

Shibuya.lispに行く人は是非ともLisp系諸言語を使ってほしい。行ったあとでもいいから書いてほしい。ただの物見遊山だったらニコ動で見たっていいと思うんだ。

Twitter / ゆきねこにゃん。
  • 「ゆきねこだって再帰書けないじゃん」というツッコミはともかく、なんとなく空気感的にこのあたりの意見には同意できる気がする
  • Shibuya.lispに少しも貢献できていないダメメンバーとしては「そろそろ言っとくか」的なエントリは心苦しい限りなんだけど
  • 毎回、すごい発表者をそろえて運営側はがんばってると思うし、発表者にも得るものがあるイベントだと思う。でも、参加者がやっぱり物見遊山的に見えてしまうんだよね、外部からは
  • 一瞬で席が埋まってしまうスピードと、終わったあとの反響の少なさのギャップというか(「そんなことない!」という反論歓迎)
  • そもそもLispを盛り上げる必要なんてあるのか、という疑問に対する答えがやっぱり見つからない気がするんだ

(引用)ギレンさんが

らんはさんの疑問

「諸君らの愛した表示的意味論(R5RS)は死んだ。なぜだ?」

と述べられた時、シャアさんはR6RSに鑑みて、ひいてはプログラミング言語意味論を思ってどう答えるのでしょうか?

教えてください。m(_ _)m

http://d.hatena.ne.jp/ranha/20090615

自分も知りたい。召還魔法はこうですか?>id:sumii先生

alohakunalohakun 2009/06/15 14:49 つ http://d.hatena.ne.jp/sumii/20080311/p2

yad-ELyad-EL 2009/06/15 14:52 ありがとうございます。さっき読んだところでした

2009-06-10

[]三文会「2011年後のテレビと動画の未来予見」

  • 初参加。メディアの役割みたいなことを最近よく考えるので、テレビの状況を知りたくて行ってみた
  • 参加者は10人ちょっとくらい。東大生を中心に、他大学の人とか社会人(たぶん東大OB)とか
  • 最初に参加者がそれぞれ1分スピーチ。お題は「テレビとネット動画とどっちをよく見るか」もしくは「人生を変えたテレビ番組」。前もってお題を把握してなかったので正直あせった
  • 実際にテレビ番組を制作していた石塚さんという方の制作現場の話が中心。すごくおもしろかった
  • 「番組の質を上げるための演出」と「やらせ」をごっちゃにしちゃうような参加者がいなかったのもよかった
  • 終わった後、参加者が感想を1分ずつ。「これからはテレビを素直に見れなくなります」というナイーブな感想に驚いてしまったのは、きっと私の心が汚れてるせい。。。
  • 石塚さんが最後に紹介した「いい爺いライダー」の話が示唆に富んでいた。感じたのは「楽しんで作る」「作りたいものを作る」「人を巻き込む」。言葉にすると当たり前のことなんだけど

【以下メモ】

  • 個人での動画配信が増える。日立のハイビジョンカメラケータイとか。そのうち動画用素材集ができるかも
  • 動画はストーリーがないと見るのは厳しい
  • 感銘を受けたのはNHK特集「のぞみ5歳」(NHKアーカイブスにある。購入可)。全盲の両親の表情がすばらしい
  • 制作に携わっていた番組の例。「愛の貧乏脱出大作戦」と「ぶらり途中下車の旅」。共通点は飲食が関係していること
  • 重要なのは三つ。「様々な事例があるか」「ユニークな人が出ているか」「話題性」。ただし話題性を意識しすぎるとブームで終わってしまうので「話題性は考えなくてもいいかな」(石塚さん)
  • 愛の貧乏に出てくる達人は喜怒哀楽が動く人でないとダメ。すぐに合格を出してしまうような人では番組が成り立たない
  • ぶらり途中下車の旅
    • 発見感が大事
    • 商店街にはキャラのいいおじさんやおばさんがいる
    • 緊張感が大切。街を歩いていて疑問に思ったことがあったら声をかける「ひとりぶらり途中下車の旅」をやってみるとか
    • 旅人は年配の人が多い。普通に話ができて相手に気をつかえる人。そうでない人は淘汰される。若い人だと難しい
  • メディアリテラシー研究会の参加者は学校の先生が多い。「TVを批判したい」という感じ。番組制作者は忙しすぎてそういう場には来ない
  • 民法のメディアリテラシ番組がおもしろい。視聴者からの意見に対する回答を楽しむ
  • 土曜朝5時「週刊フジテレビ批評」
  • 日曜朝4時50分「はい!テレビ朝日です」
  • 日テレは15分番組で、ディレクタが番組の紹介をしてるだけ
  • 再びぶらりの話
  • 6チームあってそれぞれにディレクターがいる。ディレクターの性格はばらばら
  • タレントの撮影日とブツ撮りの撮影日は別。タレントを待たせてブツ撮りはありえない。箸上げは制作スタッフがやっている。「いいものはちゃんと撮る」
  • 1日で回っているわけではない。先方の人の都合もある
  • 旅人が永島敏行の例。訪問先はビルの地下に作られた田んぼ。彼は農業の授業とかやってるくらい詳しい。若いタレントだとそういう話はできない。好きなネタだと旅人もいい表情をする
  • 会話だけで価値がある。しかも会話の制作費はタダ
  • 番組冒頭の電車の撮影は鉄道会社の許可が必要。許可を取ってないと警笛を鳴らされてしまう。他の番組は撮影料を払わなければならないが、ぶらりはタダで撮らせてくれる
  • ちい散歩はぶらりのパクリ。しかも毎日やってずるい
  • 東京メトロから「ぜひぶらりのスタッフに番組を作ってほしい」という依頼。その結果できたのが「東京日和」
  • 台本は一応ある。その訪問先で「おもしろい1点」を外さないため
  • スケジュールの話。旅人は拘束時間が決まっている。取材先に連絡しておもしろい状況を確実に用意しなければならない。時間との勝負
  • 車内の撮影は午前しかできない。午後はラッシュになってしまうため。普通に乗客がいる中で気をつかいながら撮影してる
  • 電車の乗り降りは扉の左右をあらかじめ確認しておく。カメラが左右うろうろするわけにはいかないから
  • 小学生とのふれあいの場面とか使いたいが、最近では難しい。テレビに映ったことがわかると親から学校にクレームが行くため。モンスターペアレントというわけではなく普通にそう。子供の顔を出せない世の中になってしまった
    • 地方ではまだ「タレントが来るとうれしい」というのは残っているが。それがまさに「田舎に泊まろう!」
    • スーパーの客のコメントでも最近は顔にぼかしを入れる。逆にそういうことを演出としてやるディレクタもいる
  • ロケハンのときには必ず写真を撮る。旅人になったつもりでシミュレーションする
  • NHKにはADはいない。全部一人でやる。民放はADが準備してディレクタは演出を行うだけ
  • ADは人材不足
  • ADを経ずにディレクターになってしまうと「何をやってもいい」と勘違いしてしまう危険性がある
  • 作り手が苦労する時代
  • 動画サイトの問題点。Ask.jpがつぶれることでユーザーがアップした動画がなくなってしまう。思い出が消える
  • 番組には番組ごとの文法がある
  • 放送作家の人件費カットが進んでいる。生放送が多くなっているのは制作費を削減するため
  • 新聞は5W1Hで文章を書く。一方、テレビでは10秒とか7秒で伝える含蓄のある言葉が必要になる
  • 番組の内容に応じた客が来る。ぶらりには「さっき雨降ってたのに(濡れてない)」とか細かいクレームをつける野暮な客は来ない
  • 「話しておもしろい」ということが重要。モー娘。とかスター誕生は話をできる舞台だった
  • 参加者から中村イネさんの話(これらしい)。一般人にはマネージャーがいないので、急に脚光を浴びると危ない
  • 「田んぼdeミュージカル」「田んぼdeファッションショー」「いい爺いライダー」の話
  • アラセブ(アラウンドセブンティ)
  • 崔洋一監督が応援している。93年の「月はどっちに出ている」に村がマザーズフォレスト賞を贈ったのがきっかけ
  • 中心になっている原田幸一さんは昔、電気屋さんでいろんな人の性格を知っている。プロデューサーに必要な資質
  • 神風特攻隊の生き残り。特攻服を着て出演
  • この村の人たちは道路も自分たちで作った
  • 村の名前がなくなることに反対するために映画を作った。そういうことをおもしろがる精神がクリエイティブ

[]第157回 素人くさいSICP読書会(at 三田某所)

  • 会場提供ありがとうございました
  • 参加者が少なくてへこんだ。最初3人で、最終的に6人
  • はじめの40分くらい無駄話をしてしまう
  • 新しいMacBook Proはバッテリー交換不可とか
  • ノキアのサービスは全部「Oviなんとか」とか
  • shibuya.lisp #3でshiroさんの講演があるとか
  • P爺とか
  • 5章を頭から読んだ
  • スタックマシンとレジスタマシンについて雑談
  • スタックマシンのCPUもそこそこあるらしい
  • スタックポインタはレジスタマシンでスタック領域を確保するためのものなのでスタックマシンにはない
  • ノイマン型の話に脱線
  • ハーバード・アーキテクチャの方がセキュリティが高いけど実装が大変。プログラムをデータとして扱うことができないため、ハードウエアでプログラムのロードを行う必要がある
  • 問題5.1
  • この問題では一時レジスタは不要
  • 初期化のボタンが二つと「Pへの代入ボタン」と「Cへの代入ボタン」の計4個のボタンを使う
  • 「Pへの代入ボタン」→「Cへの代入ボタン」の順に押さないと動作がおかしくなる。順番依存
  • 佐野さんがホワイトボードに書いた図↓

f:id:yad-EL:20090611003256j:image

  • 問題5.2
  • そのまま書き下すだけ
(controller
 (assign c (const 1))
 (assign p (const 1))
 test-c
   (test (op >) (reg c) (reg n))
   (branch (label fact-done))
   (assign p ((op *) (reg p) (reg c)))
   (assign c ((op +) (reg c) (const 1)))
   (goto (label test-c))
 fact-done)