如何将 monadic 函数作为参数传递给灵活类型变量?

How can I pass a monadic function as an argument with a flexible type variable?

抱歉问题标题可能含糊不清 - 我不确定如何措辞,因为我对问题的理解很差。

基本上,我如何进行以下编译? :-p

{-# LANGUAGE MultiParamTypeClasses #-}

class (Monad m) => MyClass m a where
  valM :: m (Maybe a)
  val  :: m a

f :: (MyClass m a) => (m a -> IO a) -> IO (a, Maybe a)
f g = do
  x <- g val
  yM <- g valM
  return (x, yM)

GHC (v8.2.2) 抱怨 a 是一个严格的类型变量,似乎无法处理 (g val)(g valM) 可能产生不同值的想法类型。我试过使用 RankNTypes 但无济于事。

是否有我可以用来帮助编译器的扩展,或者从 type-inference 的角度来看,是否有一些概念上与我正在尝试做的事情不符?

你是对的,你需要 RankNTypes,但你缺少一个 forallf 的正确类型是:

f :: MyClass m a => (forall b. m b -> IO b) -> IO (a, Maybe a)

...因为传递给 f 的函数必须适用于任何结果类型,并且它不应该与结果中的 a 相关。


还可能值得注意的是,这种函数也称为 自然变换 ,自然变换包为此类函数提供了 a (~>) type alias

type (~>) f g = forall a. f a -> g a

因此,使用该类型别名,您也可以这样写 f

f :: MyClass m a => (m ~> IO) -> IO (a, Maybe a)