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