Pracuję nad aplikatorem, który zawiera monoid do "wyświetlenia" wykonania. Czasami jednak nie dbam o tę część, więc wybór monoidu jest nieistotny, ponieważ nigdy nie zostanie zużyty. I zostały uproszczone, co mam na:Używanie typów więzów i rodzin typów z ograniczeniami "ograniczonymi"
{-# 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
jest wykorzystywana do przekształcania różnych a
s na pojedynczym b
. Merge
jest dużym uproszczeniem mojego faktycznego funktora, ale chodzi o to, że zawiera on rodzinę/ograniczenie typu, a moim zamiarem jest określenie dokładnie tego, czego wymaga Render
lub Merge
.
Teraz mogę chcą "run" na Merge
, ale odrzucić pogląd, który jest podobny do czegoś takiego:
runFoo :: Merge a => a -> Int
runFoo x = case merge x of() -> 5
ale to się nie powiedzie, ponieważ:
Nie można wydedukować
(Renderer a())
wynikające ze stosowaniamerge
wybrałem ()
jak mój monoid ponieważ f orall a
, mamy instancję Render a()
. Więc jeśli istnieje sposób, aby powiedzieć, że Merge a
oznacza po prostu ograniczenia zbiórki Render
to działałoby to dobrze. Oczywiście, Merge a
jest bardziej ogólne niż to - może dodać arbitralne ograniczenia, co wyjaśnia błąd kompilacji.
Czy mimo to można uzyskać to, co chcę, bez zmiany sygnatury runFoo
?
Czy 'Renderer' zawsze zawierać dokładnie jeden' Render'? –
@Tinctorius - nie, zazwyczaj zależy od ilości różnych typów w polach 'Foo' – ocharles
Czy istnieje powód, dlaczego' Merge' nie ma również 'b' jako parametru? –