次の単純な関数は、指定されたモナディック関数をNothingに達するまで繰り返し適用し、その時点で最後のNothing以外の値を返します。それは私が必要とすることを行い、私はそれがどのように機能するかを理解しています。
lastJustM :: (Monad m) => (a -> m (Maybe a)) -> a -> m a
lastJustM g x = g x >>= maybe (return x) (lastJustM g)
Haskellでの独学の一環として、可能な限り明示的な再帰を避けようとしています(または少なくともその方法を理解しています)。この場合、単純で非明示的に再帰的な解決策があるはずですが、私はそれを理解するのに苦労しています。
のモナディックバージョンのようなものは必要ありませんtakeWhile
。これは、Nothingより前の値をすべて収集するのに費用がかかる可能性があり、とにかくそれらを気にしないためです。
Hoogleの署名を確認しましたが、何も表示されません。ここm (Maybe a)
ではモナド変換子が役立つかもしれないと少し思わせますが、詳細を考え出すのに必要な直感はまだありません。
おそらく、これを行うのは恥ずかしいほど簡単であるか、それができない、またはできない理由を理解するのは恥ずかしいほど簡単ですが、私が教育戦略として自己恥ずかしさを使用したのはこれが初めてではありません。
更新:もちろん、使用する代わりに述語を提供することもできます:(述語が真である最後の値を返す)のMaybe
ようなものも同様に機能します。(a -> Bool) -> (a -> m a) -> a
私が興味を持っているのは、標準のコンビネータを使用して、明示的な再帰なしでどちらかのバージョンを作成する方法です。
背景:コンテキストの簡略化された作業例を次に示します。単位正方形内のランダムウォークに関心があるとしますが、出口のポイントのみを考慮します。次のステップ関数があります。
randomStep :: (Floating a, Ord a, Random a) =>
a -> (a, a) -> State StdGen (Maybe (a, a))
randomStep s (x, y) = do
(a, gen') <- randomR (0, 2 * pi) <$> get
put gen'
let (x', y') = (x + s * cos a, y + s * sin a)
if x' < 0 || x' > 1 || y' < 0 || y' > 1
then return Nothing
else return $ Just (x', y')
のようなものevalState (lastJustM (randomStep 0.01) (0.5, 0.5)) <$> newStdGen
は、新しいデータポイントを提供します。