web-dev-qa-db-ja.com

モナディックアクションから値を抽出する方法

シグネチャ:: (Monad m) => m a -> aの組み込み関数はありますか?

Hoogleはそのような機能はないと言っています。

理由を説明できますか?

モナドは2つの関数のみを提供します:

return :: Monad m => a -> m a
(>>=) :: Monad m => m a -> (a -> m b) -> m b

これらはどちらもm a型の値を返すため、これらを組み合わせてMonad m => m a -> a型の関数を取得する方法はありません。そのためには、これらの2つの関数以外にも必要なものがあり、モナドであるということよりもmについて詳しく知る必要があります。

たとえば、IdentityモナドにはrunIdentity :: Identity a -> aがあり、いくつかのモナドには同様の機能がありますが、一般的に提供する方法はありません。実際、モナドから「エスケープ」できないことは、IOのようなモナドにとって不可欠です。

51
hammar

おそらくこれよりも良い答えがありますが、型(Monad m) => m a -> aを使用できない理由を確認する1つの方法は、nullモナドを検討することです。

data Null a = Null

instance Monad Null where
    return a = Null
    ma >>= f = Null

(Monad m) => m a -> aNull a -> aを意味します。つまり、何もないところから何かを取得します。それはできません。

25
Owen

Monadは分解用のパターンではなく、合成用のパターンであるため、これは存在しません。それが定義するインターフェースと一緒に、いつでもより多くのピースを置くことができます。何かを分解することについては何も言っていません。

何かを取り出すことができない理由を尋ねるのは、JavaのIteratorインターフェースに、反復する対象に要素を追加するメソッドが含まれていない理由を尋ねるのと同じです。 Iteratorインターフェースの目的ではありません。

そして、一種の抽出関数を持つ特定の型についてのあなたの引数は、まったく同じ方法に従います。 Iteratorの特定の実装には、add関数がある場合があります。しかし、それがIteratorsの目的ではないため、特定のインスタンスでのそのメソッドの存在は関係ありません。

そして、fromJustの存在も同様に無関係です。これは、Monadが説明する動作の一部ではありません。他の人は、extractで作業する価値のない型の例をたくさん挙げています。しかし、これらの型は、Monadの意図されたセマンティクスを引き続きサポートしています。これは重要。これは、Monadが、あなたが認めているよりも一般的なインターフェースであることを意味します。

17
Carl

そのような関数があったとしましょう:

extract :: Monad m => m a -> a

これで、次のような「関数」を書くことができます。

appendLine :: String -> String
appendLine str = str ++ extract getLine

extract関数が終了しないことが保証されていない限り、appendLine "foo"の結果は(a)"foo"以外のものに依存するため、これは参照透過性に違反します。異なるコンテキストで評価した場合の異なる値。

あるいは、もっと簡単に言えば、実際に役立つextract操作があった場合、Haskellは純粋に機能しません。

11
Luis Casillas

シグネチャ:: (Monad m) => m a -> aの組み込み関数はありますか?

Hoogleが存在しないと言った場合は、おそらく存在しません。「組み込み」の定義が「ベースライブラリ内」であると想定します。

Hoogleはそのような機能はないと言っています。理由を説明できますか?

Hoogleがそのタイプシグネチャに一致する関数をベースライブラリで見つけられなかったので、それは簡単です!

もっと真剣に、私はあなたがモナドの説明を求めていたと思います。問題は安全性意味です。 (また参照してください magicMonadUnwrap :: Monad m => m a -> a)に関する以前の私の考え

タイプ[Int]の値があると言ったとしましょう。 []がモナドであることはわかっているので、これはMonad m => m Int型の値があることを伝えるのと似ています。それでは、Int[Int]から取得したいとします。さて、どのIntが欲しいですか?最初の1つ?最後の?私があなたに言った値が実際に空のリストである場合はどうなりますか?その場合、あなたに与えるIntさえありません!したがって、リストの場合、単一の値を試して抽出するのはunsafeです。安全(空ではないリスト)の場合でも、リスト固有の関数(たとえば、head)を使用して、自分の意味を明確にする必要がありますf :: [Int] -> Intを希望する。うまくいけば、ここからMonad m => m a -> a意味が十分に定義されていないことを直感的に理解できます。同じモナドに対して複数の意味を持つこともあれば、一部のモナドに対してまったく何も意味しないこともあり、場合によっては単に安全ではないこともあります。

7
Dan Burton

それは意味をなさないかもしれないからです(実際にはdoesは多くの場合意味を成しません)。

たとえば、次のようにパーサーモナドを定義します。

data Parser a = Parser (String ->[(a, String)])

現在、Parser StringからStringを取得する適切なデフォルトの方法はまったくありません。実際、モナドだけで文字列を取り出す方法はまったくありません。

6
Cubic

http://hackage.haskell.org/package/comonad-5.0.4/docs/Control-Comonad.html には、便利なextract関数と、これに関連する他のいくつかの関数があります。 =

これは一部のファンクタ/モナドに対してのみ定義されており、必ずしも全体の答えを与えるわけではなく、anの答えを与えます。したがって、comonadのサブクラスが存在する可能性があり、制御を行うことができる答えを選択する中間段階を提供します。おそらくTraversableの可能なサブクラスに関連しています。そのようなことがどこで定義されているのかわかりません。

Hoogleがこの関数をまったくリストしない理由は、comonadパッケージがインデックス付けされていないためであると思われます。そうでない場合、モナド制約が警告され、extractComonadインスタンス。おそらくこれは、フーグルパーサーが不完全であり、一部のコード行で失敗するためです。

私の代わりの答え:

  1. 型のコンストラクタをインポートした場合は、再帰的なケース分析を実行できます。
  2. 抽出した値を使用するコードをモナドにリンクすることができます。代わりのコード構造としてmonad >>= \a -> return $ your code uses a hereを使用し、出力を出力する方法でモナドを "IO()"に変換できる限り、完了しました。これは抽出のようには見えませんが、数学は現実の世界とは異なります。
1
codeshot

まあ、技術的には、IOモナド用の nsafePerformIO があります。

しかし、名前自体が示すように、この関数は悪であり、あなたが本当に何をしているのかを知っている場合(そして、あなたが知っているかどうかを尋ねてください、それからあなたはしません)

0
hugomg