2

Apologies for the potentially vague question title - I'm not sure how to phrase it because I have a pretty poor understanding of what the problem is.

Basically, how do I make the following compile? :-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) complains that a is a rigid type variable and can't seem to cope with the idea that (g val) and (g valM) could produce values of different types. I've tried using RankNTypes but to no avail.

Is there an extension I can use to help the compiler, or is there something conceptually broken with what I'm trying to do from a type-inference point of view?

4

1 回答 1

8

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

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

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


还可能值得注意的是,这种函数也称为自然转换,而自然转换包为此类函数提供(~>)类型别名:

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

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

f :: MyClass m a => (m ~> IO) -> IO (a, Maybe a)
于 2018-01-01T21:16:10.277 回答