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

时间:2018-01-01 21:07:01

标签: haskell monads typeclass rank-n-types

对潜在模糊的问题标题表示道歉 - 我不确定如何表达它,因为我对问题的理解很差。

基本上,我如何进行以下编译? :-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,但无济于事。

我是否可以使用扩展来帮助编译器,或者从类型推断的角度来看,是否存在一些概念上的错误?

1 个答案:

答案 0 :(得分:8)

你是对的,你需要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)