2014-10-28 3 views
2

패턴 일치/가드를 사용하여 a 함수를 쓸 수 있습니까? 주 (state) 모나드 (monad) 필드에서 일치를 패닝하는 방법은 무엇입니까?

{-# 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' :: State MyState String 
a' | i <- gets counter, i == 0 = return "hello" 

a를 작성 시도했지만 오류 가지고 :

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" 

답변

8

이 불가능합니다. 패턴 보호 구문의 왼쪽 화살표는 do 표기법의 왼쪽 화살표와 관련이없는 이고 대부분입니다.

{-# 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" 
+2

LambdaCase가 매우 좋습니다. –

+0

나는 람다 케이스를 골랐다. 덕분에 –

+0

모든 브랜치가'return'으로 시작했기 때문에'(<&>) = flip fmap'을 다음과 같이 다시 쓸 수있다 :'gets counter <&> \ case 0 -> "hello"; 1 -> "bye". '(<&>)는 렌즈 패키지에 있습니다 https://hackage.haskell.org/package/lens-4.13.2.1/docs/Control-Lens-Operators.html#v:--------62- –

2

도우미를 쓰지 않는 이유는 무엇입니까?

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

a :: State MyState String 
a = fmap doA get 

이것은 또한 순수 로직과 불순한 논리를 분리하는 철학을 따릅니다.

+0

'국가'모나드는 어떻게 불순한가? – alternative

3

아니요. 근본적으로 개념적으로 약간의 불일치가 있습니다.

패턴 식의 최상위 부분이 생성자 함수이지만 do 스타일 블록의 헤드 (이 경우 함수 >>=가 정의 정상적인 기능 될 것이다 때만 작동 일치 typeclass에서 Monad).

가드

유형 Bool의 값하지만 당신은 (모나드에 대한 독특한 것들 중 하나는 당신이 그들로부터 벗어날 수 있다는 것입니다 때문에) 그 유형 State MyState Bool의해야 할 것이다 손 겁니다 값을 기대합니다. 그래서 경비원도 일하지 않을 것입니다.

그러나 functor 인스턴스에 도달합니다. Functors는 Prelude에 정의되어 있습니다. Control.Applicative<$>이라고하는 fmap이라는 중온 형태가 있습니다. 당신은 말을하여이를 사용하는 것입니다 : 당신이 process 기능을 원하는

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

이나하고. >>=과 같은 것을 얻으려면 자신의 연산자를 flip fmap으로 정의한 다음, 예를 들어 gets counter >= \x -> case x of ...이라고 쓸 수 있습니다.

+1

패턴 가드 (Haskell 2010 이후 표준)는 일반 가드보다 강력하며'Bool '일 필요는 없습니다. 그러나이 사용 사례에서는 충분히 강력하지 않습니다. –

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 $ \ [email protected](MyState i) -> Identity $ 
    case i of 
    0 -> ("hello", s) 
    1 -> ("bye", s)