是否可以使用匹配/警卫的模式编写函数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"
答案 0 :(得分:8)
这是不可能的。模式保护语法中的左箭头大部分与标记中的左箭头无关。
如果您愿意,可以使用新的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"
答案 1 :(得分:3)
没有。这里有一些非常基本的概念不匹配。
模式匹配仅在表达式的最顶部是构造函数函数时才有效,但是do
样式块的头部将是普通函数(在本例中是类型类>>=
中定义的函数Monad
)。
警卫期望值Bool
的值,但您要提供的值必须是State MyState Bool
类型(因为其中一个独特之处)关于monads的事情是你无法摆脱它们)。所以警卫也永远不会工作。
可以但是可以到达仿函数实例。编曲在前奏中定义; fmap
中有一个名为<$>
的{{1}}的中缀形式。你可以这样说:
Control.Applicative
或使用a' = process <$> gets counter
where
process 0 = "hello"
process _ = "bye"
函数执行任何操作。要获得更像process
的内容,您还可以将自己的运算符定义为>>=
,然后您可以编写flip fmap
。
答案 2 :(得分:2)
为什么不写一个帮手?
pureA :: MyState -> String
pureA (MyState 0) = "hello"
pureA (MyState 1) = "bye"
pureA _ = ""
a :: State MyState String
a = fmap doA get
这也遵循将纯逻辑的关注点与不纯的逻辑分开的哲学。
答案 3 :(得分: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)