Подтвердить что ты не робот

Полиморфизм внутри монадов

Я пытаюсь извлечь значение из монады, но сохраняю значение, которое не зависит от монады, полиморфное. В частности:

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

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

Дело в том, что монадическая часть вычисления является дорогостоящей для вычисления, поэтому я хочу сделать это только один раз, сохраняя значение в полифонии монады. Все мои попытки до сих пор:

  • давая x подпись forall a. (Ring a) => a)
  • предоставление foo :: (Monad mon) => mon (forall a . (Ring a) => a)
  • включение -XNoMonomorphismRestriction и NoMonoLocalBins

либо не работали, либо давали ошибки об импрессивном полиморфизме, которые я не желаю использовать. Есть ли какой-то способ вывести полиморфное значение из монады без импертивирующего полиморфизма (или, альтернативно: существует ли безопасный способ использования недифференцирующего полиморфизма в GHC)?

4b9b3361

Ответ 1

Вы можете обойти отсутствие непроизводительного полиморфизма путем переноса полиморфного значения в специальный тип данных.

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

foo :: Monad m => m AnyRing

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

Ответ 2

Я нашел еще одно интересное решение, которое появилось из этой статьи на типизированных, безрезультатных, окончательных интерпретаторах (раздел 2.3).

Идея заключается в использовании "дубликатора":

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 (оно работает только тогда, когда монадическое значение является экземпляром класса типа), но это интересно, потому что вам не нужен полиморфизм более высокого ранга.