monad 内部的多态性

Polymorphism inside monads

我正在尝试从 monad 中提取一个值,但保留 value,它不依赖于 monad,是多态的。具体来说:

foo :: (Monad mon, Ring a) => mon a
foo = return 3

main :: IO ()
main = do
  x <- foo
  print (x :: Double)
  print (x :: Int)

关键是计算的 monadic 部分计算起来很昂贵,所以我只想做一次,同时保持 monad 中的值多态。到目前为止我的所有尝试:

  1. x签名forall a. (Ring a) => a)
  2. 给予foo :: (Monad mon) => mon (forall a . (Ring a) => a)
  3. 启用 -XNoMonomorphismRestrictionNoMonoLocalBins

要么没有工作,要么给出了有关命令多态性的错误,我不愿意使用。有没有什么方法可以在没有谓词多态的情况下从 monad 中提取多态值(或者:有没有一种安全的方法可以在 GHC 中使用谓词多态)?

您可以通过将多态值包装在特殊数据类型中来解决缺少指示多态性的问题。

newtype AnyRing = AnyRing (forall a. Ring a => a)

foo :: Monad m => m AnyRing

main = do
  AnyRing x <- foo
  print (x :: Double)
  print (x :: Int)

我发现了另一个有趣的解决方案,它来自 this paper on typed, tagless, final interpreters(第 2.3 节)。

想法是使用 "duplicator":

data Dup a b = Dup a b

duplicate :: Dup a b -> (a,b)
duplicate (Dup a b) = (a,b)

instance (Num a, Num b) => Num (Dup a b) where
  fromInteger x = Dup (fromInteger x) (fromInteger x)
  ...

foo :: (Monad mon, Num a) => mon a
foo = return 3

main :: IO ()
main = do
 x <- foo
 let (y,z) = duplicate x
 print (y :: Double)
 print (z :: Int)

这个解决方案不像 Li-yao Xia 的那样通用(它只适用于 monadic 值是类型的实例 class),但它很有趣,因为你不需要更高的 -等级多态性。