fakedrake
fakedrake

Reputation: 6856

Default values subject to existential constraint in haskell

Consider the following typeclass that defines pairs of types:

class Constraint a b where
  g :: a -> b

For all instances of constraint we can derive a set of types a, essentially an implicit typeclass, let's call it A. For each instance of typeclass A there is another implicit typeclass B which is includes all possible types b for Constraint A b.

So here is a piece of code.

{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE MultiParamTypeClasses #-}
import Debug.Trace

-- Contraining class
class (Show a, Show b) => QandA a b where
  g :: a -> b

-- Some data types
data A = A1 | A2 deriving (Show, Eq)
data B = B1 | B2 deriving (Show, Eq)
data C = C1 | C2 deriving (Show, Eq)

instance QandA A B where
  g A1 = B1
  g A2 = B2

instance QandA A C where
  g A1 = C1
  g A2 = C2

-- We want to define a set of types that includes all the types that
-- have Constraint a b given a. This can be done via an intermediate
-- type.
data DefaultAnswer q = forall a . (DefaultingQuestion q, QandA q a) => DefaultAnswer {answer :: a};

-- Polymorphism
class DefaultingQuestion q where
  def :: DefaultAnswer q

instance DefaultingQuestion A where
  def = DefaultAnswer C1

Which typechecks but in ghci

> (def :: DefaultAnswer A)
(def :: DefaultAnswer A) :: DefaultAnswer A

But

> answer (def :: DefaultAnswer A)
<interactive>:574:1:
    Cannot use record selector "answer" as a function due to escaped type variables
    Probable fix: use pattern-matching syntax instead
    In the expression: answer (def :: DefaultAnswer A)
    In an equation for "it": it = answer (def :: DefaultAnswer A)

Now the way I understand it is that, since I use existential types, GHC does not really look for the type of answer, it just makes sure there could be one even if it has no way of figuring out which one it is. So then when I actually want to run answer it can't figure out how to deal with it.

So my question is: is there a way to define a default answer for each type that implements DefaultingQuestion

Upvotes: 0

Views: 151

Answers (1)

sclv
sclv

Reputation: 38893

Why not:

import Data.Proxy

class DefaultingQuestion q a where
  def :: Proxy q -> a

instance DefaultingQuestion A where
  def _ = C1

Upvotes: 1

Related Questions