Haskell: 与命名字段的模式匹配
Haskell: Pattern matching with named fields
我从 Control.Monad.Reader
得到 ReaderT
:
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
和 Action
来自 Database.MongoDB.Query
:
type Action = ReaderT MongoContext
MongoDB的查询函数是这样的:
delete :: MonadIO m => Selection -> Action m ()
我正在尝试对 Action m ()
使用模式数学来检查它是 Action IO ()
还是 Action _ ()
像这样的简单案例
case x of
Action IO () -> True
Action _ () -> False
不起作用,因为 Action
不是数据构造函数。也许我应该使用这样的东西:
case x of
ReaderT MongoContext IO () -> True
ReaderT MongoContext _ () -> False
但是我得到一个错误:
The constructor ‘ReaderT’ should have 1 argument, but has been given 3
In the pattern: ReaderT MongoContext IO ()
In a case alternative:
ReaderT MongoContext IO ()
我应该传递 MongoContext -> IO ()
吗?我没有想法,请帮我解决这个问题。谢谢 <3
IO 是一种类型,你绝对不能大小写匹配它,它只存在于编译时。
一般来说,如果你有一个受类型class约束的类型变量,你只能调用该类型class支持的东西。除非 typeclass 实现检查它的方法,如 Typeable
,否则您无法知道它是哪种特定类型。 Monad
和 MonadIO
都没有实现这种 运行 时间类型区分,所以你想要的在设计上是不可能的。
另请注意,您不需要知道 "which m" delete
是什么,因为它专用于您想要的任何 m
,只要它是MonadIO
的实例。您可以简单地声明 deleteIO sel = delete sel :: Action IO ()
您实际上想在这里完成什么?
As Steven Armstrong said, what you're trying to do is very weird, you cannot pattern match on IO because is an abstract data type (constructors aren't visible) and if I were you I would rethink what I'm trying to achieve. Having said that, Haskell still gives you a way of inspecting types at runtime using Typeable 例如(在 ghci 会话中):
import Data.Typeable
import Control.Monad.Trans.Reader
type MyType = ReaderT String IO
f :: MyType ()
f = ReaderT $ \env -> putStrLn env
checkF :: Typeable a => MyType a -> Bool
checkF x = case show (typeOf x) of
"ReaderT * [Char] IO ()" -> True
_ -> False
-- checkF f => True
我从 Control.Monad.Reader
得到 ReaderT
:
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
和 Action
来自 Database.MongoDB.Query
:
type Action = ReaderT MongoContext
MongoDB的查询函数是这样的:
delete :: MonadIO m => Selection -> Action m ()
我正在尝试对 Action m ()
使用模式数学来检查它是 Action IO ()
还是 Action _ ()
像这样的简单案例
case x of
Action IO () -> True
Action _ () -> False
不起作用,因为 Action
不是数据构造函数。也许我应该使用这样的东西:
case x of
ReaderT MongoContext IO () -> True
ReaderT MongoContext _ () -> False
但是我得到一个错误:
The constructor ‘ReaderT’ should have 1 argument, but has been given 3
In the pattern: ReaderT MongoContext IO ()
In a case alternative:
ReaderT MongoContext IO ()
我应该传递 MongoContext -> IO ()
吗?我没有想法,请帮我解决这个问题。谢谢 <3
IO 是一种类型,你绝对不能大小写匹配它,它只存在于编译时。
一般来说,如果你有一个受类型class约束的类型变量,你只能调用该类型class支持的东西。除非 typeclass 实现检查它的方法,如 Typeable
,否则您无法知道它是哪种特定类型。 Monad
和 MonadIO
都没有实现这种 运行 时间类型区分,所以你想要的在设计上是不可能的。
另请注意,您不需要知道 "which m" delete
是什么,因为它专用于您想要的任何 m
,只要它是MonadIO
的实例。您可以简单地声明 deleteIO sel = delete sel :: Action IO ()
您实际上想在这里完成什么?
As Steven Armstrong said, what you're trying to do is very weird, you cannot pattern match on IO because is an abstract data type (constructors aren't visible) and if I were you I would rethink what I'm trying to achieve. Having said that, Haskell still gives you a way of inspecting types at runtime using Typeable 例如(在 ghci 会话中):
import Data.Typeable
import Control.Monad.Trans.Reader
type MyType = ReaderT String IO
f :: MyType ()
f = ReaderT $ \env -> putStrLn env
checkF :: Typeable a => MyType a -> Bool
checkF x = case show (typeOf x) of
"ReaderT * [Char] IO ()" -> True
_ -> False
-- checkF f => True