第3回 スタートHaskell 感想

今回はニフティで開催。大森駅には初めて降りた。住宅街とオフィス街が混ざったような雰囲気だった。

発表

極意

バグの入り込みにくい小さな関数をつなげて、大きな関数を作る。

速度

length は遅い。あと rverse も。配列をすべて走査しないといけないから。途中で打ち切れない。

再帰

「一つ前ができていたら、次はどうする?」(c) 和田先生.

畳み込み

foldr は末尾再帰でない再帰。遅延評価と相性がいい。リストを生成する関数と相性がいい。
foldl は末尾再帰。数値を生成する関数と相性がいい。
and や or を 畳み込みを使って実装する場合は、リストを生成する関数ではないが foldr の方がいい。

and' :: [Bool] -> Bool
and' = foldr (&&) True

and の場合 (&&) の定義が

True  && x = x
False && _ = False

となっているため、途中で False が見つかればそこで処理を打ち切れる。末尾再帰を使うと以下のようなコードの場合、返ってこない。

and $ map (<= 10) [1..]

演習

型(Kata)の練習。3時間は長いな〜と思ったけど、あっという間だった。
虎さんが用意してくださった演習はとてもやりやすかった。いつもありがとうございます。

Sinatra, OmniAuth メモ

遅ればせながら OmniAuth を使ってみた。とても便利だったのでメモしておく。

サンプル

https://github.com/ymmtmsys/sinatra_omniauth_sample

  • Sinatra, Omniauth, Slim
  • Twitter のアプリ登録では、Access level を Read and write にしておく必要あり。

手順

Step 0

https://dev.twitter.com/ でアプリを登録。登録時に発行される Consumer key, Consumer secret は後で使う。

Step 1

Gemfile を作成して。bundle install を実行。

% bundle install
Step 2

config.ru を作成。

Step 3

app.rb を作成。

Step 4

環境変数の設定。 Step 0 で得た Consumer key, Consumer secret を設定。

% export TWITTER_CONSUMERKEY=Consumer key
% export TWITTER_CONSUMERSECRET=Consumer secret
Step 5

起動。ブラウザで動作確認。

% bundle exec rackup config.ru

第2回 スタートHaskell 感想

今回は参加者が 100 名以上いた前回までとは違い、50名強の参加者だった。人が少ないなと思ったが、勉強会としては多い方だろうな。

第 1 部

予習してきた部分の発表。発表だけかと思いきや熱い議論が始まる展開に。初心者向けの勉強会と銘打たれているが、Haskellに詳しい方も参加されているので、いろいろとためになる話が聞けてよかった。

第 2 部

演習。本当に初心者向け?皆さん解くのが速い。

elem は中置記法

Haskeller は

elem 'c' "abcdefg"

よりも

'c' `elem` "abcdefg"

と書く人が多いらしい。英語のように読むことができるので。elem に限った話ではないけど。

-Wall -O

ghc(i) の実行時には -Wall と -O のオプションを付けるべし。-Wall は警告をすべて表示させる。-O は最適化を行う。gcc のオプションと同じ。
ただ問題が。-Wall を付けることで実行時に警告が出力される場合がある。コンパイル時には警告は出ない。これはちょっと使いづらい。

% ghci -O -Wall section7_13.hs
GHCi, version 7.0.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package ffi-1.0 ... linking ... done.
[1 of 1] Compiling Main             ( section7_13.hs, interpreted )
Ok, modules loaded: Main.
*Main> nmerge [[9],[2,5,7],[1,4],[],[3,6],[8]]

<interactive>:1:37:
    Warning: Defaulting the following constraint(s) to type `Integer'
               (Num a0) arising from the literal `8' at <interactive>:1:37
               (Ord a0) arising from a use of `nmerge' at <interactive>:1:1-6
    In the expression: 8
    In the expression: [8]
    In the first argument of `nmerge', namely
      `[[9], [2, 5, 7], [1, 4], [], ....]'

<interactive>:1:37:
    Warning: Defaulting the following constraint(s) to type `Integer'
               (Num a0) arising from the literal `8' at <interactive>:1:37
               (Ord a0) arising from a use of `nmerge' at <interactive>:1:1-6
               (Show a0) arising from a use of `print' at <interactive>:1:1-39
    In the expression: 8
    In the expression: [8]
    In the first argument of `nmerge', namely
      `[[9], [2, 5, 7], [1, 4], [], ....]'
[1,2,3,4,5,6,7,8,9]

書き方が悪いのかと思ったが http://haskell.org/ghc/docs/7.0.3/html/users_guide/options-sanity.html を見ると、-fwarn-type-defaults が原因のようだ。なので -fwarn-type-defaults をなくしてみる。オプションは -fno-warn-... とすることで off にすることができる。

% ghci -O -Wall -fno-warn-type-defaults section7_13.hs
GHCi, version 7.0.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package ffi-1.0 ... linking ... done.
[1 of 1] Compiling Main             ( section7_13.hs, interpreted )
Ok, modules loaded: Main.
*Main> nmerge [[9],[2,5,7],[1,4],[],[3,6],[8]]
[1,2,3,4,5,6,7,8,9]

消えた。毎回打つのは面倒なので ~/.ghci にオプションを追加。
~/.ghci

:set -O
:set -Wall
:set -fno-warn-type-defaults

Haskell のコードを書いていてよくハマるのが数値の型変換のところ。fromRational, toRational って何ですか。

*Main> :t fromRational
fromRational :: Fractional a => Rational -> a
*Main> :t toRational
toRational :: Real a => a -> Rational

英語が不得意な自分のために書いておくと

Rational   -- 有理数
Real       -- 実数
Fractional -- 分数

有理数と分数の違いが...。
クラスの階層関係は http://www.sampou.org/haskell/report-revised-j/basic.html#standard-classes で。数関連のクラスは複雑。

MySQL で既存の非 TEMPORARY テーブルと同名の TEMPORARY テーブルを作成する方法

テストで TEMPORARY テーブルを使いたかったときの話。

Good

CREATE TEMPORARY TABLE
    tbl_name
SELECT
    *
FROM
    tbl_name
LIMIT 0                 -- テーブルだけを作成したいときに

ただし

CREATE TABLE ... SELECT は自動的にインデックスを作成しません。

http://dev.mysql.com/doc/refman/5.1/ja/create-table.html

なので、インデックスが必要な場合には別途作成する必要がある。

Bad

LIKE だと名前が重複しているぞ、というエラーになった。

CREATE TEMPORARY TABLE
    tbl_name
LIKE
    tbl_name 

第1回 スタートHaskell 感想

会場に着いたのが 19 時 10 分頃。ちょうど勉強会が始まる頃だった。

発表

今回の勉強会の対象の 2, 3, 4 章のまとめの発表。基本的には本に書かれている内容なので新たな発見は少なかった。

コメントはネストできる。

複数行のコメントは {- -} で囲む。コメントの中にコメントを含められる。

{-
    {-
        ここはコメント
    -}
    ここもコメントになる
-}

C言語などで使われる /* */ を使ったコメントアウトではこうはいかない。

n + k パターンがなくなった理由

パターンマッチにはデータ構成子しか使えない。

演習

補足の演習問題の量が多いので、あらかじめ練習問題は済ませておいた方がいいと思った。問題の答え合わせがなかったので、これでいいのかどうなのかがわからない。今回の範囲の内容であればそれでもいいかもしれないが、先へ進んだ場合に答え合わせ+解説がないとつらいかもしれない。

宿題

今やってます。

Sequel で別名を付けたりテーブルを指定したりする

Sequel でカラムに別名を付けたり、どのテーブルのカラムなのかを指定する方法のメモ。

require 'sequel'
DB = Sequel.sqlite
Sequel::Model.plugin :schema

class Tbl < Sequel::Model
  unless table_exists?
    set_schema do
      primary_key :id
    end
    create_table
  end
end
                                                                                                                                
p Tbl.select(:id).filter(:id => 1).sql
# => "SELECT `id` FROM `tbls` WHERE (`id` = 1)"
p Tbl.select(:id___pk).filter(:tbls__id => 1).sql
# => "SELECT `id` AS 'pk' FROM `tbls` WHERE (`tbls`.`id` = 1)"
p Tbl.select(:tables__id___pk).sql
# => "SELECT `tables`.`id` AS 'pk' FROM `tbls`"

カラム名 + "___" + 別名 で別名を付ける。
テーブル名 + "__" + カラム名 で テーブルを指定。


アンダーバーを使ったカラム名は避けたい。

ツイッターの認証で毎回アプリの許可画面が出る件について

今作っている Web アプリでツイッターの OAuth 認証をする際、毎回このアプリを許可するかどうかの確認画面が表示されていた。以前作ったアプリではそんなことはなかった。
調べたら、認証用の URL は oauth/authenticate と oauth/authorize の 2 種類があった。
今のアプリが使っているのは oauth/authorize だったので、oauth/authenticate に変えてみたところ、アプリの許可確認画面は表示されなくなった。ちなみに、許可確認画面の表示/非表示の違いがその 2 つの本質的な違いではない。
デスクトップアプリでは必ず oauth/authorize の方を使えとあるが、今作っているのは Web アプリなので oauth/authenticate を使うことにして解決。