ushidayの日記

主に「IBMi」のメモに・・・

第三回Haskell読書会

第三回Haskell読書会が静岡市民文化会館で、開催され無事終了致しました。
スピーカーのid:kynbitさん、高校生という若さでLTをしてくれたSupakiくん、関係者並びにご参加頂いた皆様ありがとうございました。
ついつい話が脱線しがちな中、kynbitさん曰く、「今回の第四章のテーマは、あくまでも”関数の定義する方法を学ぶ”」という、かの名言で直ぐに軌道修正。前回よりも会場利用時間が、30分短いという中、ハンズオンを中心にまとめて頂き、充実していたのではと思います。

関連ブログ

本章の内容については、参加メンバーが既に、ブログで書かれているので、そちらで雰囲気を感じて頂けたらと。


おやつ

2開催連続で、代表のたかはしさんが、タマゴ型プリン&たまごボーロを、仕入れてきてくれました。ありがとうございます。そしてウマイ!頭使って糖分補給コレ基本です。たまごボーロも懐かしいです。口の中の水分みんな持っていかれる感じが何とも言えない。
(「eatたまごボーロ :: たまごボーロ → 口の中砂漠化」「drinkお茶 :: お茶 → 口の中オアシス」)


SupakiくんLT

最年少のSupaki君が、TwitterをテーマにLTをやってくれました。
Twitterのキモは”おやじギャグなんだ!”と教わりました。高校生にして、アラサーやアラフォーのオッサン相手に、OpenOfficeでスライド作るなんてすごい経験だよ。将来有望です。

練習問題1を2次会で「あーだこーだ」

本章の練習問題1は以下の様な内容でした。

要素数が偶数のリストを引数にとる関数「halve」は、要素数の真ん中で2分割したリストのタプルを返す。
つまり...
halve [1,2,3,4,5,6]
>([1,2,3],[4,5,6])
になれば良いと

kynbitさんから、追加の課題で「奇数の時は、リストを返さないでエラーを...」。しかし終了時間を迎え、急いで片付け、そのまま懇親会へ。そして2次会で、「奇数でエラーって型宣言しているから、空リストのタプル返すくらい?」みたいな話で、「まぁ、それだけでもやってみようYo!」とバーでPC引っ張り出してきて「あーだこーだ」。(何やってんだろ?)
Haskellとしては(関数型としては?)、当たり前の事が、やはりいざキーボード叩いてみると、上手くいかなかったり、面白い発見もあったり、とりあえずの結論が出たところで、2次会は解散。そんな中で、where節を改めて考えてみました。

バーで追加課題をやっていた時、まずこういう書き方で、Parseエラー

-- parse error on input `|'
halveBar::[a]->([a],[a])
halveBar xs | (length xs `mod` 2) == 0 = (take (myLen) xs ,drop (myLen) xs)
                where  myLen  =  length xs `div` 2
            | otherwise =  ([],[])

halveBar::[a]->([a],[a])
halveBar xs | (length xs `mod` 2) == 0 = (take (myLen) xs ,drop (myLen) xs)
            | otherwise =  ([],[])
                where  myLen  =  length xs `div` 2

こっちはOK。where節を細かくやっていないので、自分が語ると間違っていそうで、アレなのですが、調べてみると...。

    • where節は、直前の束縛の右辺に対して作用する。
    • where節は、直前の束縛より深いインデントでなければならない。

確かにガードは、「if then else if then else ...〜」のシンタックスシュガーみたいなモノだから、前の例だとthenとelseの間にイキナリwhereを入れている様なもので、よくよく考えればおかしい。つまりこうしているのと同じ

halveBar::[a]->([a],[a])
halveBar xs = if (length xs `mod` 2) == 0 
                    then  (take (myLen) xs ,drop (myLen) xs)
                            where  myLen  =  length xs `div` 2   -- if ならせんヤロ
                    else  ([],[])

halveBarの束縛に対して、whereで局所定義するなら、普通にこうなる。

halveBar::[a]->([a],[a])
halveBar xs = if (length xs `mod` 2) == 0 
                    then  (take (myLen) xs ,drop (myLen) xs)
                    else  ([],[])
                            where  myLen  =  length xs `div` 2

ifだと間違えない、それはそんな処にwhere入れたら、違和感を感じるから。でもガードみたいな見慣れない、シンタックスを拝んだりすると、変な錯覚をしてしまい、違和感を感じない。(そもそもガードの書き方に違和感を感じたり。見やすくて好きなんですけどね、^_^ガード。自分ガード派です。今のところ...)あーダメな自分を再認識しました。そして理解した上でまとめ。

halve::[a]->([a],[a])
halve xs | myEven = (take myHalfLen xs ,drop myHalfLen xs)
         | otherwise =  ([],[])
  where 
     myLen      =  length xs                     --リストの長さ
     myHalfLen  =  myLen `div` 2                 --リストの半分の長さ
     myEven     |  (myLen `mod` 2 ) == 0 = True  --要素数の偶数判定
                |  otherwise = False

whereは直前の束縛の右辺に対して作用とあるが、上の記述は正しく動いているので、同一where内の束縛に対しても有効みたい。(myLenはmyEvenなどでもスコープ出来ているので...。)これは、結果論なので、本当に正しいのかはチト不安な気もします。
スコープでダメな例は以下のような場合。

--     Not in scope: `myHalf'
--   Failed, modules loaded: none.

halveNG::[a]->([a],[a])
halveNG xs | myEven = (take myHalfLen xs ,drop myHalfLen xs)
           | otherwise =  ([],[])
  where 
     myLen      =  length xs
     myHalfLen  =  myLen `div` myHalf  -- myHalfはスコープできない。
     myEven     |  (myLen `mod` myHalf ) == 0 = True
                |  otherwise = False
        where myHalf = 2

この場合は、それぞれwhere節が下のように、必要になる。

halveNG::[a]->([a],[a])
halveNG xs | myEven = (take myHalfLen xs ,drop myHalfLen xs)
           | otherwise =  ([],[])
  where 
     myLen      =  length xs
     myHalfLen  =  myLen `div` myHalf
        where myHalf = 2
     myEven     |  (myLen `mod` myHalf ) == 0 = True
                |  otherwise = False
        where myHalf = 2

今回はひょんなことから、where節の理解が少し深まりました。次回の第4回は三島で行うことに決定しました。また正式に決まり次第告知させて頂きます。
2010.7.24(土)のグランシップ開催だけは、リアルガンダム東静岡に初お披露目とあって、早速会場をキープしました。;-)