4

Stateモナドを と組み合わせる方法を理解しようとして、脳をねじって結び目を作っていMaybeます。

State数値のリストの合計を求めるためにモナドを使用する具体的な (そして意図的に自明/不必要な) 例から始めましょう:

import Control.Monad.State

list :: [Int]
list = [1,4,5,6,7,0,3,2,1]

adder :: Int
adder = evalState addState list

addState :: State [Int] Int
addState = do
  ms <- get
  case ms of
    []     -> return 0
    (x:xs) -> put xs >> fmap (+x) addState

涼しい。

Nothingリストに number が含まれている場合に を返すように変更しましょう0。つまり、evalState addState' listを返す必要がありますNothing( がlist含まれているため0)。こんな感じかも…と思いました。

addState' :: State [Int] (Maybe Int)
addState' = do
  ms <- get
  case ms of
    [] -> return (Just 0)
    (0:xs) -> return Nothing
    (x:xs) -> put xs >> fmap (fmap (+x)) addState'

...動作しますが、これを行うためのより良い方法があると思います...

StateTandをいじってみましたがMaybeT、それらを機能させることができません。Monad トランスフォーマーの紹介をいくつか見てきましたが、この特定の組み合わせ (State + Maybe) に触れていなかったか、例が複雑すぎて理解できませんでした。

TL;DR:StateT and MaybeT(2 つの例)を使用して、この (確かに些細な) コードを記述する方法を誰かが示すことができれば幸いです。(トランスフォーマーを使わずにこのコードを書くことは不可能だと思います - それは間違っていますか?)

PS私の理解では、StateTおそらくこの例により適していますが、それほど面倒ではないにしても、両方の例を見ることは概念的に役立ちます。

更新: @Brenton Alker が指摘したように、上記のコードの最初のバージョンは単純なタイプミス (アポストロフィがありませんでした) のために機能しません。StateT/の使用に関する質問に焦点を当てるために、MaybeT上記の投稿を修正しています。彼の投稿にコンテキストを与えるために、このメモを含めたかっただけです.

4

3 に答える 3

8

私が使用することをお勧めするタイプは次のとおりです。

StateT [Int] Maybe Int

Maybe/を使用する非常に簡単な方法は、失敗したいときと、失敗した計算から回復したいときはいつでもMaybeT呼び出すことです。これは、他のモナドトランスフォーマー内に階層化されていても機能します。mzeromplus

次に例を示します。

addState' :: StateT [Int] Maybe Int
addState' = do
  ms <- get
  case ms of
    []     -> return 0
    (0:xs) -> mzero
    (x:xs) -> put xs >> fmap (fmap (+x)) addState

-- This requires generalizing the type of `addState` to:
addState :: Monad m => StateT [Int] m Int

Maybe固有の操作を使用しないように書いたことに注意してください。実際、コンパイラに型シグネチャを推測させると、代わりにこのより一般的な型が推測されます。

addState' :: MonadPlus m => StateT [Int] m Int

これStateTは、次のMonadPlusインスタンスがあるため機能します。

instance MonadPlus m => MonadPlus (StateT s m) where ...

AndMaybeは のインスタンスとして型チェックします。これが、 に特化しMonadPlusたときに上記のコードが機能する理由です。mMaybe

于 2014-11-24T02:16:47.853 に答える
1

あなたの解決策は基本的に正しいと思います。いくつかの小さな問題があるだけです。

  1. への再帰呼び出しにaddState素数がありません。そうあるべきですaddState'(報告されたエラーを考えると、これは質問を貼り付ける際の問題にすぎないと思います)
  2. あなたは をアサートしていますadder :: Intが、新しいバージョンではそうあるべきですadder :: Maybe Int- これはあなたが得ている型エラーだと思います。

残念ながら、現時点ではトランスフォーマー バージョンを試すリソースがありません。

于 2014-11-24T02:17:29.663 に答える