2

私はMonad、ReaderT、...を台無しにして、「単純な?」を実行しています。行動。

Maybeテスト関数を変換 (Maybeまたは別のパーソナライズされたモナド)に散在させたいと考えています。

まさに、私tは呼び出しを避けて、ある種のモナド(モナドだと思う)を作成したい

doCalculus :: (Int -> Bool) -> Int -> Maybe Int
doCalculus f a = do
  b <- t $ a + 1
  c <- t $ 2 * b
  d <- t $ a + b + c
  return d
  where t = if f n then Just n else Nothing

test :: Int -> Bool
test n = not (n `elem` [3, 7, 9])

*Main> doCalculus test 2
Nothing
*Main> doCalculus test 3
Just 15
*Main>

私はReaderTいくつかのようなモナドを実行しようとしています

runMaybeTest doCalculus test

として使用する

doCalculus :: Int -> Maybe' Int
doCalculus a = do
  b <- a + 1
  c <- 2 * b
  d <- a + b + c
  return d

perform = runMaybe' doCalculus test

しかし、私はできません。

(もちろん、Int型はモナドにジェネリックになります)

ヒントをありがとう!

=== 更新 1 ===

できます!:) ...しかし、実用的ではありません(私は思う):(

私は素晴らしいエリックキッドの投稿を採用しました

import Prelude hiding (Just, Nothing, return, (>>=))

class Tester a where
  test :: a -> Bool
  test _ = True

data MMaybe a = Nothing | Just a deriving (Eq, Show)

class Monad1 m a where
  return :: a -> m a
  fail :: String -> m a

class (Monad1 m a, Monad1 m b) => Monad2 m a b where
  (>>=) :: m a -> (a -> m b) -> m b

instance (Tester a) => Monad1 MMaybe a where
  return = Just
  fail _ = Nothing

instance (Tester a, Tester b) => Monad2 MMaybe a b where
  Nothing >>= _ = Nothing
  (Just x) >>= f = if test x then f x else Nothing

instance Tester Int where
  test n = not $ n `mod` 2 == 0 && n `mod` 3 == 0

test1 :: Int -> MMaybe Int
test1 n =
  return n >>= \a ->
  return (a + 3) >>= \b ->
  return (a + b)

test2 = map test1 [1..20]

考えられる(重要な)問題は次のとおりです。

  1. 使えるモナドですか?
  2. do表記はどこですか?
  3. テスト関数を一意の型に定義するだけで動作します (新しいテスト関数には新しい型が必要です)

しかし、テスト関数を疑似モナドにラップできます... (それは何かです)

4

2 に答える 2

6

(a) いくつかの変換をシーケンス化し、(b) さまざまな段階で述語の失敗を短絡させたいと考えているようです。このプロセス全体は、「含まれる」型 (ここでは Int) と述語に対してパラメトリックです。

飛び込みましょう。

ここで制御している主な影響は失敗であるため、Maybe開始するのに最適な場所です。そのMonadインスタンスにより、さまざまな を生成するMaybe計算を構成できます。

-- some pure computations
f, g, h :: a -> a

-- ... lifted and sequenced!
may :: a -> Maybe a
may = (return . f) >=> (return . g) >=> (return . h)

これは非常に儀式的な書き方(h . g . f)です。なぜなら、完全に一般的な「モナディック」(実際にはKleisli) 合成を使用しており、特殊効果を使用していないからです。

Ⅱ.

predicatep :: a -> Boolを指定すると、失敗し始める可能性があります。これを行う最初の方法は、MaybeMonadPlusインスタンスとを使用することguard :: MonadPlus m => Bool -> m ()です。

\a -> do x <- return (f a)
         guard (p x)
         y <- return (g x)
         guard (p y)
         z <- return (h y)
         guard (p z)
         return z

しかし、ここではかなり繰り返されるパターンがあることは明らかです --- 純粋な関数のすべての「構成境界」で、述語を実行し、失敗する可能性があります。これは、あなたが考えたように -likeReaderと-like 効果の強力な混合ですが、それらのいずれかまたはそれらのスタックMaybeとまったく同じ ic セマンティクスを持っていません。Monad他の方法でキャプチャできますか?

III.

さて、それらをまとめてみましょう。

newtype OurMonad a = OM { getOM :: MaybeT (Reader (a -> Bool)) a }

とを含むモナド変換子スタックのOurMonad周りです。これを利用して、非常に一般的な「実行」関数を作成できます。newtypeReaderMayberunOurMonad :: (a -> Bool) -> OurMonad a -> Maybe a

というか、できそうな感じですよね?実際にはできないと主張したい。その理由は、インスタンスを書くためにはinstance* をMonad持たなければならないからです。問題は、述語を一般化する方法を一般的に知らないことです! 関数**も持たない限り、関数を書く方法がわかりません。Functora -> bOM a -> OM b(a -> b) -> (a -> Bool) -> b -> Boolb -> a

したがって、これを に一般化しようとして行き詰まっていますMonad。一つではないと思います。

IV.

Endoしかし、あなたの例は、Monad の完全な一般性を実際には必要としませんでしたa -> a。これは、単一の述語で十分な方法の 1 つです。Endo型の同質性を利用して、 のリストをとして書くことができます[a -> a]。では、もう少し直接的に必要なものをfoldそのリストの上に定義してみましょう。

stepGuarded :: (a -> Bool) -> a -> [a -> a] -> Maybe a
stepGuarded pred = foldM $ \a f -> mfilter pred (return $ f a)

stepGuarded (`elem` [3, 7, 9]) 3 [ (+1), (*2) ] 
-- Nothing

stepGuarded (`elem` [4, 8, 9]) 3 [ (+1), (*2) ]
-- Just 8

* nb 技術的には正しくありませんが、理論的にも実用的にも、インスタンスを作成できない場合は、インスタンスのFunctor作成も滞ってしまいMonadます。

** 技術的には、これは依然として categoricalFunctorであり、ファンクタが共変であるFunctorと仮定すると、反変です。Monadこれらすべてを一般化して同型の関手を持つことができます。Edward Kmett はこれらを s と呼んでおり、代わりExFunctorに定義することができます。これは素晴らしいことです。xmap :: (a -> b) -> (b -> a) -> f a -> f b

于 2013-02-22T01:56:48.043 に答える
0

あなたがする必要があるのは、do ブロックで「let」を使用することだと思います。

doCalculus :: Int -> Maybe Int
doCalculus a = do
  let b = a + 1
  let c = 2 * b
  let d = a + b + c
  return d

また

doCalculus :: Int -> Maybe Int
doCalculus a = Just d where
  b = a + 1
  c = 2 * b
  d = a + b + c

do 表記をすべてスキップします。

于 2013-02-22T00:36:06.203 に答える