Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Polymorphism inside monads

Tags:

haskell

ghc

I'm trying to pull a value out of a monad, but keep the value, which doesn't depend on the monad, polymorphic. Specifically:

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

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

The point is that the monadic portion of the computation is expensive to compute, so I only want to do it once, while keeping the value in the monad polymorphic. All of my attempts so far:

  1. giving x the signature forall a. (Ring a) => a)
  2. giving foo :: (Monad mon) => mon (forall a . (Ring a) => a)
  3. enabling -XNoMonomorphismRestriction and NoMonoLocalBins

have either not worked or given errors about impredicative polymorphism, which I'm not willing to use. Is there some way to pull a polymorphic value out of a monad without impredicative polymorphism (or alternatively: is there a safe way to use impredicative polymorphism in GHC)?

like image 721
crockeea Avatar asked Mar 31 '17 04:03

crockeea


People also ask

What problem do monads solve?

Monad is a simple and powerful design pattern for function composition that helps us to solve very common IT problems such as input/output, exception handling, parsing, concurrency and other. Application becomes less error prone.

What is the use of monads?

A monad is an algebraic structure in category theory, and in Haskell it is used to describe computations as sequences of steps, and to handle side effects such as state and IO. Monads are abstract, and they have many useful concrete instances. Monads provide a way to structure a program.

What is monads in programming?

In functional programming, a monad is a software design pattern with a structure that combines program fragments (functions) and wraps their return values in a type with additional computation.

Is list a monad?

List as a data structure is not a Monad, but the fact that Scala's List implements flatMap is what gives it its monadic super-powers. It also needs to fulfil associativity, left unit and right unit laws to qualify as a Monad.


2 Answers

You can work around the absence of impredicative polymorphism by wrapping the polymorphic value in a special data type.

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

foo :: Monad m => m AnyRing

main = do
  AnyRing x <- foo
  print (x :: Double)
  print (x :: Int)
like image 163
Li-yao Xia Avatar answered Nov 12 '22 09:11

Li-yao Xia


I found another interesting solution, which came from this paper on typed, tagless, final interpreters (section 2.3).

The idea is to use a "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)

This solution isn't as general as Li-yao Xia's (it only works when the monadic value is an instance of a type class), but it is interesting because you don't need higher-rank polymorphism.

like image 4
crockeea Avatar answered Nov 12 '22 10:11

crockeea