Subdivision Category について
CWM は 圏論の基礎のこと。
@taiki45 ε( ε^o^)э CWM p.224にあるでし〜 S:Cop \prod C -> Xのendとsubdivision catでのS^$のlimitが同型なんでし〜〜〜
— みょん (@myuon_myon) 2014, 2月 3
@taiki45 ε( ε^o^)э めっちょざっくり言うと、ある圏にf:b->cって射があったら、このことからf,b,cが対象でb->f, c->fを射にもつ圏が作れるんでし〜 これをもとの圏のsubdivision categoryというんでし〜
— みょん (@myuon_myon) 2014, 2月 3
@taiki45 ε( ε^o^)эε( ε^o^)э でしでし〜 実は函手Sのsub. cat.でのlimitとSのendが同型になってなかなか面白いんでし〜〜〜 ε( ε^o^)эε( ε^o^)э
— みょん (@myuon_myon) 2014, 2月 3
@taiki45 ε( ε^o^)э そうでしよ〜〜
— みょん (@myuon_myon) 2014, 2月 3
Haskell の newtype の使いどころ
newtype、まだつかったことないでし…
— (deffish *tai*) (@taiki45) 2014, 2月 3
newtypeはその制約のおかげで構造を入れやすいから汎用的な構造つきデータを表現するのに便利 typeは型に別名を与えたいときとか型変数に「意味」をもたせたいときに便利
— みょん (@myuon_myon) 2014, 2月 3
あとtypeだと既存の函数が同じように流用できるので、typeで宣言したものに対する操作を再定義する必要がないからportablityが上がる(Lensみたいに)
— みょん (@myuon_myon) 2014, 2月 3
そもそもtypeとnewtypeは使い所が全然違うのでどっちがいいとかいうようなものではないと思いますけどね
— みょん (@myuon_myon) 2014, 2月 3
typeってほんとにタダの別名でしかないので可読性上げる以上の意味あるのかなってずっと思ってるマン #だから基本newTypeの方が良くねっていう長年の疑問
— co1row.jp (@co1rowjp) 2014, 2月 3
data書いてみて型コンストラクタが*->*だったらnewtypeにするっての、良くやる。
— ちゅーん (@its_out_of_tune) 2014, 2月 3
@taiki45 newtype宣言は実行時には捨てられてるから、単にその方がパフォーマンス良いだけでつ。一般的な使い方はパスベルスが言ってるように、既存の型に制約とか別の性質を与えたりするのに使いますベルス。
— ちゅーん (@its_out_of_tune) 2014, 2月 3
@taiki45 うい(´・ω・`)
— ちゅーん (@its_out_of_tune) 2014, 2月 3
同じ中身に違う性質を持たせたい→newtype
同じ性質に違う名前を持たせたい→type
— ふみ(DJ Monad) (@fumieval) 2014, 2月 3
typeのすごく簡単な例で、filter関数の特殊な例を出したりする。filterBook :: BookFilter -> BookList -> BookList みたいなの。
— ちゅーん (@its_out_of_tune) 2014, 2月 3
type BookFilter = Book -> Bool
— ちゅーん (@its_out_of_tune) 2014, 2月 3
このBookFilterっていう別名、idxFilter :: Int -> BookFilterとか、nameFilter :: String -> BookFilterみたいな関数考えてようやく効果が解ってくる(´・ω・`)
— ちゅーん (@its_out_of_tune) 2014, 2月 3
まぁ、ぶっちゃけ、このくらいならやらないけど(´>ω∂`)
— ちゅーん (@its_out_of_tune) 2014, 2月 3
typeのコメント的な使い方は変数名で十分なことが多い
— Kasio Hino (@hiyakashi_) 2014, 2月 3
newtypeでなくてtypeを使う意味は「これは単なる、わかり易くするための型の別名である」って事を明記するためなのねん。
— ちゅーん (@its_out_of_tune) 2014, 2月 3
newtype は GeneralizedNewtypeDeriving を使うときよく使う
— パスベルス (@pasberth) 2014, 2月 3
type で宣言すると,できなくていい操作もできてしまうので newtype で宣言して必要なものだけ deriving するのが好きです
type MyType = String
newtype MyType = MyType String deriving IsString
— パスベルス (@pasberth) 2014, 2月 3
たとえば String に対して異なる Monoid の定義を与えたいとかの場合は newtypeにします
— パスベルス (@pasberth) 2014, 2月 3
type で alias をつけるのと, newtype で宣言してすべての性質(型クラス)をderivingで継承するのとは基本的に同じことです.
— パスベルス (@pasberth) 2014, 2月 3
たとえば C_1, C_2, .., C_n っていう型クラスのインスタンスである T があるとします.以下の2つはほとんど同じです:
type U = T
newtype U = U T deriving (C_1, C_2, .., C_n)
— パスベルス (@pasberth) 2014, 2月 3
たとえば t :: T と f :: U -> W とがあったとき, type の場合は f t のように呼べますが newtype の場合は f (U t) のように呼ばなくてはならないなど,コンストラクタを介さないと値をつくれないという違いはありますが,
— パスベルス (@pasberth) 2014, 2月 3
性質としては同じものだと考えられます.このことから, type で別名をつけることは, newtype でもできるといえます(newtypeですべての型クラスをderivingすればよろしい).
— パスベルス (@pasberth) 2014, 2月 3
また,すべての型クラスをderiving *していない* 場合の newtype は, type に制約をつけたものと考えられます.つまり type で別名をつけることに,特定の型クラスは継承しない,という制約をつけたものが newtype であるということです.
— パスベルス (@pasberth) 2014, 2月 3
そういう理由で「typeで書いたものはnewtypeでも書ける」とか「typeは必要ない操作もできてしまうのでnewtypeのほうが好き」と発言した次第です
— パスベルス (@pasberth) 2014, 2月 3
ちゅーんさんは型コンストラクタが邪魔にならないtype宣言は好きでつ。愛用しまくりんぐ。
— ちゅーん (@its_out_of_tune) 2014, 2月 3
関数の型にtypeで別名を付けるのは慎重にならなければいけない
— ふみ(DJ Monad) (@fumieval) 2014, 2月 3
newtypeとtypeの同質性って、A:X→F(X), B:F(X)→Xとした時、Id_X=B〇Aになる、とか多分そんなん。
— ちゅーん (@its_out_of_tune) 2014, 2月 3
newtypeをtype的に使うの完全に無意味感がある(そういうふうにも使える、という意味ではあれだけど議論する価値はあるのだろうか)
— 中2女子南山まさかず (@PG_nonen) 2014, 2月 3
なんだろう、typeとnewtypeを比較してるの、C++でclassの合成を使った擬似的なstrong typedefとtypedefを比較しているような感覚でなんかこううーん違和感
— 中2女子南山まさかず (@PG_nonen) 2014, 2月 3
目的も用途も違う機能を比較するのもなぁって気もするのだけれどううむ……むむむ……
— 中2女子南山まさかず (@PG_nonen) 2014, 2月 3
さっきも言ったけどむしろdataの特殊な場合の最適化用のものだと思っているのでdataと比較したほうがいいのでは……ううむ……
— 中2女子南山まさかず (@PG_nonen) 2014, 2月 3
僕としてはnewtypeはkindが*->*の場合のためのdataの代わり的なものがやはり意図されているんじゃないかという気がしてしまう(確かなことは設計者に聞くしか無い)
— 中2女子南山まさかず (@PG_nonen) 2014, 2月 3
まあ、dataとtypeの両方の性質と用途を適当にゴチゃっと合いの子にしてそれぞれちょいとずつ制限した感じのものがnewtype、ってのが正解なのかもしれない
— 中2女子南山まさかず (@PG_nonen) 2014, 2月 3
newtype はやはり名前にもある通り type に近いもので, type に制約を課せる機能だと思う.
— パスベルス (@pasberth) 2014, 2月 3
type は暗黙のうちにすべての型クラスを deriving して,暗黙の型変換(コンストラクタを介さなくても値をつくれる)を定義してくれるnewtypeなんですよ
— パスベルス (@pasberth) 2014, 2月 3
用途で比べるのか性質で比べるのか。
— ちゅーん (@its_out_of_tune) 2014, 2月 3
性質で言うなら、なんやかやdataとnewtypeが近いぽよ。IdentityとMaybe。
— ちゅーん (@its_out_of_tune) 2014, 2月 3
newtype aとaは同型
— みょん (@myuon_myon) 2014, 2月 3
@taiki45 newtype HexRGBA = HexRGBA Word32 ってやると 0xFFFFFFFF みたいな整数リテラルをRGBAカラー空間座標的に扱う方として利用できる(ということは CSS とか OpenGL 相手にする時に… あとはわかるね?)
— ぼうくん (@VoQn) 2014, 2月 3
@taiki45 FizzBuzz の例でも見せたけど、 型宣言するとリテラル相手にした時に引数はデータコンストラクタ呼ばなくても newtype 宣言した”それ”として扱われて便利なのよ。 show (3 :: FizzBuzz) これで済む
— ぼうくん (@VoQn) 2014, 2月 3
構成子が一つしかない&&構成子は固定の型&&データコンストラクタも1種しかない&&特定の型クラスのインスタンスとしての振る舞いは変えたい場合は newtype 使う(たぶん適切な用法は別にまだある)
— ぼうくん (@VoQn) 2014, 2月 3
@taiki45 よくあるパターンは cabal からもらって来る代数的データ型が便利でいいのだけど、自分が利用してる際に微妙にある型クラスとしての実装が歯がゆくなった時に、エイヤとnewtypeするケースとか。
— ぼうくん (@VoQn) 2014, 2月 3
@taiki45 あるいは自分が定義した型クラスを、プリインor外部ライブラリの型のインスタンスとして宣言するのに、影響範囲を限定したい時(自前モジュール内だけそうしたい)とか。ただこれあまりないケース
— ぼうくん (@VoQn) 2014, 2月 3
@taiki45 たぶん newtype の一番の真価は既存型に対して、型クラスのインスタンス宣言を「モジュールのAPIが果たすべきコンテキスト」に合わせて、他のモジュールと疎結合の状態で書き換えられる術がユーザーに与えられてる事
— ぼうくん (@VoQn) 2014, 2月 3
@taiki45 やろうと思えば代数的データ型をドメインオブジェクトのように、newtype で コンテキストに合わせ振る舞いを変えたように見せ、 型クラスを持ってインタラクションを、といった DCI 紛いの事はできると思うよ
— ぼうくん (@VoQn) 2014, 2月 3
newtype の強力さ、なんていうか『邪王炎殺黒龍波の真の力』みたいな説明になりがち…
— ぼうくん (@VoQn) 2014, 2月 3
GeneralizedNewtypeDeriving… ほむほむ…
— (deffish *tai*) (@taiki45) 2014, 2月 3
ついにnewtypeの本当の力に気づいてしまったか…
— Hideyuki Tanaka (@tanakh) 2014, 2月 3
ε( ε^o^)эほむほむほむほむ
おまけ
きさま、newtypeか
— 卒業しちゃう仮面 (@naota344) 2014, 2月 3
ε( ε^o^)эわろたでし
Haskell と monadic IO について(続)
もっとわかりやすい文章を見つけてしまった… ァ… ァ…
http://www.haskell.org/haskellwiki/IO%E5%85%A5%E9%96%80%E7%B7%A8
Haskell と monadic IO について書く
Haskell では IO を理解するのが難しい。さらにそれがモナドなので2重に???になる。最近この2つをわけて考えれるようになったので書いてみたい。(書いてみた結果、無駄文感するのでつらい)
想定する読者
この文章はモナドに対する説明ではなく、Haskell の IO モナドに対する説明という感じです。 ちなみにこの文章での "Haskell" は "Haskell 1.3 以降の Haskell" のことです。
Haskell と IO
Haskell は純粋関数型言語です。純粋関数型言語であるということは「外界を変える力」がないということです。
ということは純粋であるためには入力も受け取れないし、出力もできない。それがキーボードからでもネットワークからでもです。それでは実用的プログラムとしては失格です。
なので純粋関数型プログラミング言語にも IO は必要です。さてどうしましょう?
IO アクションという考え方
pure な世界と IO を分離するために IO アクションという考え方があります。IO を書いた時に、それは行われず、実際にはあとでする、というものです。純粋関数型言語でない言語では(例えば C とか)は IO が書いてあるとその評価の際に実際に IO が行われます。
それでは具合がよろしくないので、まず Haskell は main
という関数をプログラムのエントリーポイントに据えました。プログラムを実行するということは main
を実行することと等しい、という感じです。まず main 関数を呼び出すという言い方でも良いかもしれません。
さらに main
関数の型を IO a
という型に限定しています。この IO
という型は IO アクションの型です。つまりこれから行われる IO を表した型です。(1/4/2014 追記: main
は IO a
という型であってました http://itpro.nikkeibp.co.jp/article/COLUMN/20070206/260872/?ST=develop&P=3)
この IO
という型はそれだけではただのアクションなのでなにも起こりません。なので Haskell はプログラム起動時にこの main
という IO アクションに対してコマンドライン引数とか与えたりして実行するのです。
Haskell ランタイムが面倒を見てくれるので、私達は IO アクションを main
と定義をすることにより実行できるようになりました。
main = getLine
main = putStrLn $ show (10 * 3)
こうしてプログラムに絶対必要な不純な部分に対してランタイムレベルで隠蔽することで、対処することができました。めでたしめでたし。
ちょっとまって!"出力" という不純な部分には対処できたけど "入力" には対処できてない!!!
純粋と不純の切り分け
実用的なプログラムを書くために、入力を純粋な関数と受け渡ししたいという欲求があります。入力をもとに計算して出力を返したいのです。IO アクションはすばらしいですが、このままでは半分役立たずなので拡張をしましょう。
まずは、IO アクションを実行した結果を取り出して純粋な関数に受け渡すということができれば良いです。これは getValue :: IO a -> a
みたいな関数があれば足りるでしょう。
getValue
は良いアイディアに思えます。しかし、純粋な部分と不純な部分を分ける、という目的を考えましょう。もし、getValue :: IO a -> a
みたいな関数があった場合、悲惨なことが起きることが想像できます。そう、純粋な関数に不純をもちこむことができてしまうのです。
-- getLine :: IO String -- read :: String -> Int -- getValue :: IO a -> a -- getN :: (String -> Int) $ (IO a -> a) (IO String) -- getN :: (String -> Int) String getN :: Int getN = read $ getValue getLine addN :: Int -> Int addN x = x + getN
幸運なことにこのコードは動きません。getValue
なんて危険な関数はありませんので。
さらにいうと、私達は1つの IO アクションとして main
を定義しなければなりません。getValue
という関数が存在した場合、プログラムの様々な部分に IO アクションが散らばってしまいますので、IO アクションで上手くいっていたランタイムレベルでの隠蔽はできなくなってしまいます。
「IO アクションから値を取り出す」ために「getValue
のような関数を用意する」のは却下です。ではどうすればよいでしょうか?
入れ物という考え方の便利パターン is モナド
私達がしたいのはどういうことなのかもう一度書いてもいいですか?入力を受け取って、入力をもとに計算して、出力を返す、ということをしたいのです。つまり、入力という IO アクション、純粋な計算、出力という IO アクション、という3つを、ひとつの IO アクションにまとめたいのです。
そこで出てくるのがモナドというアイディアです。入れ物に対して関数を適用することはファンクターでもできます。これで「入力に対して純粋な計算をする」という私達の目的の一部は達成できます。
fmap ((+ 1) . read) getLine
つぎに必要なのは IO アクション(この IO アクションはただの IO アクションかもしれませんし、純粋な計算を適用した IO アクションかもしれません)を受け取ってひとつの IO アクションにまとめる方法です。これは join
を使えばできそうですが、ユーザーレベルだときっとランタイムレベルの隠蔽を上手くできません。なので、IO
型構築子や join
や IO アクションを受け取って IO アクションを返す関数とかを提供する代わりに、普通の値をとって IO アクションを返す関数と bind
が定義されているのではないでしょうか。
fmap ((+ 1) . read) getLine >>= putStrLn . show -- よく見るのは出力側に計算をまとめる形 getLine >>= putStrLn . show . (+ 1) . read
こうすれば複数の IO アクションと純粋な計算な計算からひとつの IO アクションを組み立てることができます。ひとつの IO アクションにまとめられるなら IO アクションという考え方はうまく機能しますね。ヤッター!!
けつろん
モナドを使うことで Haskell はランタイムレベルで IO を隠蔽しつつ私達に便利を提供しているのでした、チャンチャン。
あとがき
Mac OS X 10.9 mavericks で Haskell 環境をうまく構築する
ghc と cabal、大変でした。ということでうまくいく方法のメモ。
まずは ghc 7.6.3 と cabal-install をなんらかの方法で入れる
homebrew なり Macports なり Haskell-Platform なりで入れます。
cabal のリポジトリをクローンしてビルド
- https://github.com/haskell/cabal から clone します
cd cabal/cabal-install
cabal update
git checkout cabal-install-v1.18.0.2
cabal install
これで新しい cabal
が ~/.cabal/bin/cabal
に無事入ります。
あとは cabal-dev
使うなり、hsenv
使うなりどうぞです。
cabal install したいなら cabal-dev でし…!
Haskell の cabal、よく dependency-hell になってアッアッなのでし… なので cabal-dev がいいよってけっこう前からいろんな人がいってたのでし。
ということで使い方を覚えた記録でし…!
git clone git://github.com/creswick/cabal-dev.git cd cabal-dev cabal update cabal install
これで cabal-dev がインストールされるでし…! あとは cabal-dev の使い方でし。
- yesod をインストールする時
cabal-dev install --sandbox=~/.cabal-dev/yesod yesod-platform yesod-bin
ぼくはまだ yesod-platform 単品でしか試してないけどたぶんうまくいくとおもうでし…! エンジョイ Haskell なのでし…!
リンク
とても参考になった記事 http://myuon-myon.hatenablog.com/entry/2013/02/12/185717
ありがたや〜ありがたや〜 https://github.com/creswick/cabal-dev
最近見た Ruby のデザインパターン
最近 Capistrano, Cucumber となんかのコードを読んで思ったのが、DSL 提供する的なライブラリはConfigure
が主なインスタンスになるの多いなあと。
Configure
的なクラスに、ライブラリの主な振る舞いを include
して、パースしたりしたライブラリ側のオプションにアクセスできるようにして、最後にユーザー設定をどんどん飲み込ませていって、はい動け。っていうの多い。
ぼくも DSL 作る時は参考にしよう。