2

aパターンマッチング/ガードを使用して関数を書くことは可能ですか?

{-# LANGUAGE PatternGuards #-}
import Control.Monad.State.Strict(State, gets, runStateT)
data MyState = MyState
    { counter :: Int
    } deriving (Show)


a :: State MyState String
a = do
    i <- gets counter
    case i of
        0 -> return "hello"
        1 -> return "bye"

run = runStateT a ( MyState{counter=0} )

aとして書いてみました。

a' :: State MyState String
a' | i <- gets counter, i == 0 = return "hello"

しかし、エラーが発生しました:

No instance for (Control.Monad.State.Class.MonadState MyState m0)
  arising from a use of ‘gets’
The type variable ‘m0’ is ambiguous
Note: there are several potential instances:
  instance Control.Monad.State.Class.MonadState s m =>
           Control.Monad.State.Class.MonadState
             s (Control.Monad.Trans.Cont.ContT r m)
    -- Defined in ‘Control.Monad.State.Class’
  instance (Control.Monad.Trans.Error.Error e,
            Control.Monad.State.Class.MonadState s m) =>
           Control.Monad.State.Class.MonadState
             s (Control.Monad.Trans.Error.ErrorT e m)
    -- Defined in ‘Control.Monad.State.Class’
  instance Control.Monad.State.Class.MonadState s m =>
           Control.Monad.State.Class.MonadState
             s (Control.Monad.Trans.Except.ExceptT e m)
    -- Defined in ‘Control.Monad.State.Class’
  ...plus 12 others
In a stmt of a pattern guard for
               an equation for ‘a'’:
  i <- gets counter
In an equation for ‘a'’:
    a' | i <- gets counter, i == 0 = return "hello"

No instance for (Eq (m0 Int)) arising from a use of ‘==’
The type variable ‘m0’ is ambiguous
Relevant bindings include
  i :: m0 Int (bound at src/TestGen/Arbitrary/Helpers/Z.hs:18:6)
Note: there are several potential instances:
  instance Eq a => Eq (GHC.Real.Ratio a) -- Defined in ‘GHC.Real’
  instance (Eq e, Data.Functor.Classes.Eq1 m, Eq a) =>
           Eq (Control.Monad.Trans.Error.ErrorT e m a)
    -- Defined in ‘Control.Monad.Trans.Error’
  ...plus 118 others
In the expression: i == 0
In a stmt of a pattern guard for
               an equation for ‘a'’:
  i == 0
In an equation for ‘a'’:
    a' | i <- gets counter, i == 0 = return "hello"
4

4 に答える 4

8

これは不可能です。パターン ガード構文の左矢印は、do 表記の左矢印とはほとんど関係ありません。

必要に応じて、新しい lambda-case 拡張を使用できます。

{-# LANGUAGE LambdaCase #-}
a :: State MyState String
a = gets counter >>= \case
        0 -> return "hello"
        1 -> return "bye"

または、多方向の場合、おそらく?

{-# LANGUAGE MultiWayIf #-}
a :: State MyState String
a = do
    i <- gets counter
    if
      | i == 0 -> return "hello"
      | i == 1 -> return "bye"
于 2014-10-28T16:03:52.267 に答える
3

いいえ、ここには本当に根本的な概念の不一致がいくつかあります。

パターン マッチングは、式の最上部がコンストラクタdo関数である場合にのみ機能しますが、スタイル ブロックの先頭は通常の関数になります(この場合>>=、 typeclasss で定義された関数Monad)。

Guardは型の値を期待しますBoolが、渡す値は型でなければなりませんState MyState Bool(モナドの特徴の 1 つは、それらから逃れることができないことです)。したがって、ガードも機能しません。

ただし、 functor インスタンスに到達することはできます。ファンクタは Prelude で定義されています。の中置形式のcalled in があります。これを次のように使用します。fmap<$>Control.Applicative

a' = process <$> gets counter
    where 
        process 0 = "hello"
        process _ = "bye"

または、関数でやりたいことを何でもしますprocess。より似たものを得るに>>=は、独自の演算子を as として定義し、次のflip fmapように書くこともできますgets counter >= \x -> case x of ...

于 2014-10-28T16:28:03.950 に答える
2

ヘルパーを書いてみませんか?

pureA :: MyState -> String
pureA (MyState 0) = "hello"
pureA (MyState 1) = "bye"
pureA _           = ""

a :: State MyState String
a = fmap doA get

これは、純粋なロジックの懸念を不純なロジックから分離するという哲学にも従います。

于 2014-10-28T16:04:02.690 に答える
1

はい、可能です、そうしないことをお勧めします。

import Control.Monad.State.Strict(StateT(..))
import Data.Functor.Identity(Identity(..))

data MyState = MyState
    { counter :: Int
    } deriving (Show)

a :: StateT MyState Identity String
a = StateT $ \ s@(MyState i) -> Identity $
  case i of
    0 -> ("hello", s)
    1 -> ("bye", s)
于 2015-02-23T20:51:25.410 に答える