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,否则您无法知道它是哪种特定类型。 MonadMonadIO 都没有实现这种 运行 时间类型区分,所以你想要的在设计上是不可能的。

另请注意,您不需要知道 "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