署名付きの組み込み関数はあります:: (Monad m) => m a -> a
か?
Hoogleは、そのような機能はないと言っています。
理由を説明できますか?
モナドは次の 2 つの関数のみを提供します。
return :: Monad m => a -> m a
(>>=) :: Monad m => m a -> (a -> m b) -> m b
これらは両方とも type の何かを返すm a
ため、これらを何らかの方法で組み合わせて type の関数を取得する方法はありませんMonad m => m a -> a
。m
そのためには、これら 2 つの関数以外の関数が必要になるため、それがモナドであるということ以上のことを知る必要があります。
たとえば、Identity
モナドには がrunIdentity :: Identity a -> a
あり、いくつかのモナドには同様の機能がありますが、それを一般的に提供する方法はありません。実際、モナドから「脱出」できないことは、 のようなモナドにとって不可欠ですIO
。
おそらくこれよりも良い答えがありますが、型を持てない理由を確認する 1 つの方法は(Monad m) => m a -> a
、null モナドを検討することです。
data Null a = Null
instance Monad Null where
return a = Null
ma >>= f = Null
Now(Monad m) => m a -> a
は を意味しますNull a -> a
。つまり、何もないところから何かを得るということです。そんなことはできません。
これはMonad
、分解のパターンではなく合成のパターンであるため、存在しません。それが定義するインターフェースを使用して、いつでもより多くのピースを組み合わせることができます。何かを分解することについては何も言いません。
何かを取り出すことができない理由を尋ねることは、Java のIterator
インターフェースに、繰り返し対象に要素を追加するためのメソッドが含まれていない理由を尋ねるようなものです。それはIterator
インターフェースの目的ではありません。
そして、ある種の抽出関数を持つ特定のタイプに関するあなたの議論は、まったく同じ方法で続きます。の特定の実装には機能Iterator
がある場合がありadd
ます。しかし、それはIterator
s の目的ではないため、特定のインスタンスでのそのメソッドの存在は関係ありません。
の存在もfromJust
同様に無関係です。Monad
これは、説明することを意図した動作の一部ではありません。extract
他の人は、取り組む価値のない型の例をたくさん挙げています。しかし、これらの型は の意図したセマンティクスを引き続きサポートしMonad
ます。これは重要。これはMonad
、あなたが信用しているよりも一般的なインターフェースであることを意味します。
次のような関数があったとします。
extract :: Monad m => m a -> a
これで、次のような「関数」を作成できます。
appendLine :: String -> String
appendLine str = str ++ extract getLine
関数が決して終了しないことが保証されていない限りextract
、これは参照透過性に違反します。これは、の結果が(a)appendLine "foo"
以外のものに依存し"foo"
、(b) 異なるコンテキストで評価されると異なる値に評価されるためです。
もっと簡単に言えば、実際に有用なextract
操作があったとしても、Haskell は純粋に機能するわけではありません。
署名付きの組み込み関数はあります
:: (Monad m) => m a -> a
か?
Hoogleが「存在しない」と言った場合、「組み込み」の定義が「ベースライブラリ内」であると仮定すると、おそらく存在しないでしょう。
Hoogleは、そのような機能はないと言っています。理由を説明できますか?
Hoogleは、その型シグネチャに一致する関数をベースライブラリで見つけられなかったため、これは簡単です。
もっと真剣に、あなたは単調な説明を求めていたと思います。問題は安全性と意味です。(に関する私の以前の考えmagicMonadUnwrap :: Monad m => m a -> a
も参照してください)
タイプが。の値があると言ったとします[Int]
。これはモナドであることがわかっているので[]
、これは、タイプが。の値があることを通知するのと似ていますMonad m => m Int
。Int
それで、あなたがそれから抜け出したいとしましょう[Int]
。さて、Int
あなたはどちらが欲しいですか?最初の1つ?最後は?私があなたに話した値が実際に空のリストである場合はどうなりますか?その場合、Int
あなたに与えるものすらありません!したがって、リストの場合、そのように意地悪な単一の値を抽出しようとするのは安全ではありません。安全な場合(空でないリスト)でも、必要に応じて意味をhead
明確にするために、リスト固有の関数(たとえば)が必要です。うまくいけば、あなたはここからその意味を直感することができますf :: [Int] -> Int
Monad m => m a -> a
単に明確に定義されていません。同じモナドに対して複数の意味を持つ場合もあれば、一部のモナドに対してはまったく意味がない場合もあり、場合によっては、単に安全ではないこともあります。
意味がないかもしれないからです (実際には、多くの場合意味がありません)。
たとえば、次のように Parser モナドを定義できます。
data Parser a = Parser (String ->[(a, String)])
String
現在、 aからa を取得する賢明なデフォルトの方法はまったくありませんParser String
。実際には、Monad だけでこれから文字列を取得する方法はまったくありません。
技術的には、IO モナドにはunsafePerformIOがあります。
しかし、名前自体が示すように、この関数は悪であり、自分が何をしているのかを本当に知っている場合にのみ使用する必要があります (知っているかどうかを尋ねなければならない場合は、知っていません)。