GHC 8.x勉強会 QuantifiedConstraints編

Yuji Yamamoto (山本悠滋)

2018-12-07

GHC 8.6.1から入ったQuantifiedConstraints

何ができるようになるか

どゆこと?

data Rose f x = Branch x (f (Rose f x))

instance (Eq a, forall b. Eq b => Eq (f b)) => Eq (Rose f a) where
  (Branch x1 rs1) == (Branch x2 rs2) = x1 == x2 && rs1 == rs2

どゆこと?

instance (Eq a, forall b. Eq b => Eq (f b)) => ...

の、forall b. Eq b => Eq (f b)の箇所!

何がうれしい?

こんな感じの型があって、Eqのインスタンスを定義したい

data Rose f x = Branch x (f (Rose f x))

何がうれしい?

これはよくない!

instance (Eq a, Eq (f (Rose f a))) => Eq (Rose f a)
  where
    (Branch x1 c1) == (Branch x2 c2)
       = x1==x1 && c1==c2

何がうれしい?

QuantifiedConstraintsを有効にすると!

instance (Eq a, forall b. Eq b => Eq (f b)) => Eq (Rose f a)
  where
    (Branch x1 c1) == (Branch x2 c2)
       = x1 == x1 && c1 == c2

何がうれしい?

QuantifiedConstraintsを有効にすると!

何がうれしい?

もっとうれしそうな例:

何がうれしい?

class MonadTrans t where
  lift :: Monad m => m a -> t m a

何がうれしい?

従来のMonadTransだと、👇のMonadTransが定義できない!

newtype Comp t1 t2 m a = Comp { runComp :: t1 (t2 m) a }

instance (MonadTrans t1, MonadTrans t2) => MonadTrans (Comp t1 t2) where
  lift = Comp . lift . lift

何がうれしい?

liftの第1引数が守るべきMonad mを満たせない!

• Could not deduce (Monad (t2 m)) arising from a use of ‘lift’
  from the context: (MonadTrans t1, MonadTrans t2)
    bound by the instance declaration at <interactive>:53:10-66
  or from: Monad m
    bound by the type signature for:
      lift :: forall (m :: * -> *) a. Monad m => m a -> Comp t1 t2 m a

何がうれしい?

これならできる!👍

instance
  (MonadTrans t1, MonadTrans t2, forall m. Monad m => Monad (t2 m))
  -- (MonadTrans t1, MonadTrans t2, forall m. Monad m)
  => MonadTrans (Comp t1 t2)
 where
  lift = Comp . lift . lift

何がうれしい?

そもそも、👇のように書くこともできる!

class (forall m. Monad m => Monad (t m)) => MonadTrans' t where
  lift :: Monad m => m a -> (t m) a

ちょっと不思議な点

forall m. Monad m  

みたいに書くと、型変数m

lift = Comp . lift . lift  

の中では有効でないように読めるけど、実際には有効らしい。

Generalized Abstract GHC.Genericsでの応用

力尽きたのでコピペは省略。時間が余ったらPDFを開きながら紹介しよう!