Использование видов ограничений и семейств типов с "ограниченными" ограничениями
Я работаю над аппликативным функтором, который содержит моноид для "просмотра" выполнения. Тем не менее, иногда я вообще не забочусь об этой части, поэтому выбор моноида не имеет значения, так как он никогда не будет потребляться. Я упростил то, что у меня есть:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
import GHC.Exts
class Render a b where render :: a -> b
instance Render a () where render = const ()
class Merge a where
type Renderer a b :: Constraint
merge :: Renderer a b => a -> b
data Foo = Foo Bool
instance Merge Foo where
type (Renderer Foo) m = (Render Bool m)
merge (Foo b) = render b
Render
используется для преобразования различных a
в один b
, Merge
это большое упрощение моего фактического функтора, но дело в том, что он содержит семейство типов / ограничение, и я намерен это точно указать, что Render
эрс Merge
требует.
Теперь я мог бы "запустить" Merge
, но откажитесь от представления, которое сродни чему-то вроде:
runFoo :: Merge a => a -> Int
runFoo x = case merge x of () -> 5
Но это не удастся, потому что:
Не мог вывести
(Renderer a ())
вытекающие из использованияmerge
Я выбрал ()
как мой моноид, потому что a
у нас есть пример Render a ()
, Так что, если бы был способ сказать, что Merge a
просто означает коллекцию Render
ограничения, то это будет работать нормально. Конечно, Merge a
является более общим, чем это - это может добавить произвольные ограничения, что объясняет ошибку компиляции.
Есть ли способ добиться того, чего я хочу, не меняя подписи runFoo
?
1 ответ
Это может не масштабироваться, если у вас много таких случаев, но это работает:
class Renderer a () => Merge a where
...