haskell-jp / questions #40

ああ、でもやっぱ Glasgow ノリなんですかね、単語のチョイスが
プログラミング Ruby でも使われているあたり、Haskell に限らないみたいです https://books.google.co.jp/books?id=Dif2bl2KRUYC&pg=PA368
原著の著者(の一人)はこの方かな https://en.wikipedia.org/wiki/Dave_Thomas_(programmer) イギリス人のようですね
いやイギリス人とは書いてないか。 Imperial College London で学んだ、だけですね
まあでもイギリス圏の人は wurble を使う流儀があるのだとわかりました。ありがとうございます
(ひょっとして Haskeller なら常識的なことを知らないだけかとドキドキしてた…^^;)
さておき、型クラスを OOP のインタフェースになぞらえて説明するのは有益だと思いますか?それとも有害だと思いますか? 私は、「あえて似たものを探すのなら」という限定つきであれば悪くない説明だと思っていますが、無条件に同じものだと思ってしまうと弊害がありそうで怖い説明だと感じています
弊害その1: Eq a => [a] というのは [Int] とか [Double] とかの総称ではあるけど 「同値比較できる型のものがいろいろ混じっているリスト」のことではない(そういうのが欲しいなら ghc 拡張で [forall a. Eq a => a] と書かねばならない)という点が抜けている
弊害その2: …って書こうとしたけど特定の具体例を列挙することの方が弊害な気がしてきたのでやめます^^;
はい、型クラスの説明については私も概ね同意見ですがそろそろ別スレッドにすべきじゃないかと。。。 :sweat_smile:
家に帰ってきたらすごい通知が来てた笑笑後でじっくり読みたいと思います。わざわざ長文を書いてくださった方やコメントしてくださった方ありがとうございます:blush:
半ば世間話なんですけども、serverless-haskell を使ったことある方がいたら感想を聞きたいです。今、これとは別のアプローチ (aws-lambda-haskell-runtime + SAM) で Haskell のサーバレスアプリケーションのサンプルを書いているのですが、比較材料になればと思いまして。
前に触ったときはglibcのバージョンが合わないみたいなエラーで動きませんでした :cry:
(言葉遣いの厳密さに目をつむって)ざっくりとした理解するには悪くないんじゃないかと思いますが...。
誤った記述が正しい記述より優れているということは断じてありえないと思います。誤った記述から得られるのは誤った理解のみで、いずれ修正しないといけないので時間の無駄にしかなりません。特に、最初から間違った考えを取り込んでしまったとき、その誤りを直すコストは大きいです
この記事の間違いについて明記しておきます。 http://capm-network.com/?tag=Haskell-%E5%9E%8B%E3%82%AF%E3%83%A9%E3%82%B9

型クラスとは、型の振る舞いを定義するものです。
振る舞いを持つのは関数などの操作であって、「型の振る舞い」というのは意味をなしていない表現です。
オブジェクト指向におけるクラスとは概念が異なり、Interfaceや抽象クラスに相当します。
近い意味合いを持っているのは確かです。
インスタンスとは、型クラスの制約を満たすように定義した型のことです。
インスタンスは型ではないです。
オブジェクト指向におけるインスタンス(クラスの実体)とは概念が異なり、クラスの実装(Implement)に相当します
意味合いは近いかも知れませんが、先に述べられたように、存在量化などを使わない限り同一の型で扱えないためOOPのクラスに例えるのはあまりいい考えには見えません。
条件式
意味不明でした。
Eqのインスタンスは、等価性検査の型に使われ、「==」や「/=」で比較できる型を表します。
繰り返しですがインスタンスは型ではありません。等価性検査の型というのもよく意味がわかりません。
Int、Bool、Charといった基本的なデータは全てEqのインスタンスとなります。
それら3つはEqのインスタンスですが、それらはデータ型であってデータではないです。
Ordのインスタンスは、順序を持った型に使われ、大小の比較ができることを保証する。(<)、(<=)、(>)、(>=)の四つの比較関数は全て同一の型を持ちます。
ここはおおむね正しいです。
Showのインスタンスは、文字列表現を返します。
インスタンスは値を返すものではありません。
文字列表現を返すshow関数やprint関数は、Showのインスタンスです。
関数はインスタンスとは異なる概念です。先の「インスタンスとは…型のことです」という記述とも矛盾しています。またprint関数はIOアクションを返します。
derivingキーワードを使えば,Haskellが型クラスの文脈での振る舞いを自動導出します。
「型クラスの文脈での振る舞い」の意味がわかりませんでした。実装を導出すると言いたいのでしょうか… :thinking:
自動導出できるクラスは以下の通りです。
Ixが抜けています。
勝手に補足すると、このスレッドが文脈です https://haskell-jp.slack.com/archives/C5666B6BB/p1548731081317700
インスタンスは型ではないです。
というのは?確かに Monad クラスなどのインスタンスは型コンストラクタであって型ではありませんけど、 Eq クラスについてはインスタンスは型であるといっていいのではないでしょうか?
「インスタンスを実装した型」はあるでしょうがインスタンス自体は型ではないのでは(曖昧な概念理解)
非スレッドで続けていいのか微妙なのですが、なるほど、型そのものだととらえるのは確かに理解のさまたげになりそうですね。 Int 型は Eq のインスタンスである、という言い方自体はして良いけれどそれは厳密には「Int 型には Eq のインスタンスとしての定義が存在する」というべきである、といったとこでしょうか
インスタンスはある型(間の関係)が型クラスに規定された性質を持っていることを保証する(Haskellにおける現実としては“保証したい“程度ですが)証明オブジェクトです.(過激派)
Coq ならば本当に、型クラスには「保証する性質」を表明しますよね(…といいつつ Coq は使ったことがないので伝聞知識ですが^^;)
確かに元の文章だと「インスタンスとは(中略)型のことです」となっているので、これだと「インスタンス = 型」という説明になってしまいますよね...
原文を尊重すると「ある型Aが型クラスBのインスタンスであるとは、型Aが型クラスBの制約を満たすように定義されている状態のことである」ぐらいに書いておけば大丈夫ですかね。
うーん、「型Hogeは型クラスFooのインスタンスだよ」みたいな言い方は日常的にすると思うんですが、そんなに「インスタンス is a 型」として捉えるのはダメですかね... :confused:
厳密な言い方じゃないのは事実としてもどうせ型と1対1で存在するものだし、言ってはいけないと言うほどのものではないかと思うのですが...
どっちかというとインスタンスは値なので「is 型」は理解が遠くなりません?
同意しますが、たしかに初学者には言葉遣いに気を付けた方がいいポイントなのかなという気もします。型そのものの定義とはちょっと離れたところに書けるというのは Haskell の instance 宣言の特徴でもあるので…
あと、明らかに型ではなく「型コンストラクタ」を取るクラスもいっぱいある(Functor とか Monad とか)ので、その意味でも気を付けた方がいいんだろうな、という点にも後で気づきました^^;
型と型コンストラクターをうまく総称する言葉がないので、その辺はどこで見ても曖昧になっている気がしますね。。。 :sweat:
まあ、無引数の型コンストラクタ(kind が * の型コンストラクタ)、ということにしてしまえば、全部「型コンストラクタ」でいいと思いますが。
Haskell にそこそこ慣れてからであれば、「Int 型は Num のインスタンスである」という表現をしても「Num a => の a に Int を入れることができる」という意味として把握できるので、そういう表現自体が禁止されるわけではないと思います。
その「Num a の a に Int を入れることができる」ということと同時に「この Num a => の関数には、 (+), (-), (*) などが辞書として暗黙の引数で渡されるんだ」ということがつながるぐらいイメージがつながれば、「インスタンスは型そのものではなく値のことである」というところもわかったことになると思うんですけどね^^;
「値」といった時にそれが「関数」を含む概念であるということも最初は気づきにくいところなので、なんと説明するのがいいか悩ましいところですね…
個人的には、 sort と sortBy の関係を見た時にいろいろと合点がいった覚えがあります。ああそうか、Ord ってのは単に sortBy のデフォルト値を型に対して一個だけ選べる仕組みなんだな、と。
「振る舞い」というのはオブジェクト指向でよく出てくる言葉で、
「多態=同一のインターフェイスに対してクラス毎に異なる振る舞いを定義できる」という言い方をしますよね。

これを型クラスの世界に対応させると、

- 型クラス <=> インターフェイス
- インスタンス <=> クラス

なので、「型クラスとは、型の振る舞いを定義するものです」というのは単純にズレているように思います。
あえて言うなら、振る舞いを定義しているのはインスタンス宣言(≒オブジェクト指向のクラス宣言に対応)のところになるかと。
「ズレている」に同意します。たぶんそもそも一つ一つの言葉の選び方にあまり注意を払っていないんだと思います。「どんな振る舞いを実装すべきかを宣言する」ということを「定義する」と言ってしまっているような、そんな感じのテキトーさ加減を感じます
ところで Ix が deriving 可能だというのはいまさら知りました^^; https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-780004.3.3 ここには Ix は列挙されていないので…(Ix は Prelude には含まれていないからですね)
型を行、型クラスを列とする表のセルがインスタンスという捉え方ができるので、「インスタンスは型」というのは「インスタンスはクラス」と同じくらい的はずれな表現だと思います
型コンストラクタについて補足ですが、IntやBoolなどももちろん(無引数の)型コンストラクタで、通常インスタンス宣言は型コンストラクタに対してなされるものです
https://www.haskell.org/onlinereport/haskell2010/haskellch19.html#x27-22700019.2 ここには書いてあるので、最後までちゃんと読めってことですね^^;
縦横の表のイメージはわかりやすいですね。まずはそのイメージを持つことが重要であることは同意します。ただ、そのイメージを十分に持っている前提であれば「Num のインスタンスは Int, Integer, Double など」と言って通じると思うので、要は学習レベル次第ですよね…
「型はクラスのインスタンスになる(T is an instance of C)」
「インスタンスは型である(An instance is a type such that...)」
英語で書くと違いがわかりやすいと思います
気になって標準も読んでみたんですが、どちらかというと
- 型 is an instance
- class methodsがoverloaded operations (fumiさんのおっしゃる「セル」)
と聞こえます。
https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-630004.1

すごいH本でもp.27に「ある型クラスのインスタンスである型は、...」
という記述がありますし、やっぱり一般的な理解と異なっているのではないかと思います。 :confused:
縦横の表の理解は別に特殊ではないと思うんですが、「この列のインスタンスは〇行目と〇行目に定義されている」という表現を「この列のインスタンスは〇行と〇行だ」と省略していいかどうか、じゃないですかねえ?
"T is an instance of C"を"T is an instance"と切ってしまうのは大きな飛躍があります。「IntはNumのインスタンスである」「IntはEqのインスタンスである」ではなく「Intはインスタンスである」と言っても通じないのではないでしょうか?
問題となっているのは、「型コンストラクタTは型クラスCのインスタンスである」を逆転させて「インスタンスは型である」と言ってしまったことだと捉えています
えっと、具体的にいうと、
>>インスタンスとは、型クラスの制約を満たすように定義した型のことです。
>インスタンスは型ではないです。
こっちはおっしゃるとおりの問題があると思うんですが、
>>Eqのインスタンスは、等価性検査の型に使われ、「==」や「/=」で比較できる型を表します。
>繰り返しですがインスタンスは型ではありません。
こっちは「Eq のインスタンス」の話しかしていないので指摘は言い過ぎではないかと思いました
確かに、「Eqのインスタンス」と言えば、インスタンスとなる型の集合を指していることはわかりますね
「等価性検査の型に使われ」のところがちょっとよく分からない言い方ですが、そこを除外すれば正しい事を言っているように思います
ただまあ、なんかこう、一生懸命議論する価値のある文章でないことは確かなので^^; 「忘れてください」の一言で切り捨てたのはさすがだなと思いました^^;
ところでむしろ私は
>Ordのインスタンスは、順序を持った型に使われ、大小の比較ができることを保証する。(<)、(<=)、(>)、(>=)の四つの比較関数は全て同一の型を持ちます。
のところ(fumieval さんは「ここはおおむね正しいです」とされたところ)について、怪しさを感じました。
確かに正しく解釈できる文ではありますが、なんでわざわざ「四つの比較関数」だけを取り出してたり(compare, max, min はどこにいった?)、それらが「同一の型を持ちます」とここで解説するのか?というあたりに、「これひょっとして a->a->Bool の a と a が同じ型であることを言っているんじゃないか?」という疑念が。