Допустимо ли такое использование UndecidableInstances? Альтернативы?

Я хотел бы немного поколдовать в библиотеке, позволив полиморфно деструктурировать тип продукта. Это более-менее рабочий мокап, иллюстрирующий то, что я хотел бы сделать:

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, UndecidableInstances #-} 
newtype Wrapped a = Wrapped { unwrap :: a } 

-- our example structure
ex :: (Int, (Int, Int))
ex = (1,(2,3))

class WrapDecomp x y | y -> x where
    decomp :: x -> y

instance (WrapDecomp x x', WrapDecomp y y')=> WrapDecomp (x,y) (x',y') where
    decomp (x,y) = (decomp x, decomp y)

instance WrapDecomp x (Wrapped x) where
    decomp = Wrapped


example = let w = decomp ex
              (w0, w1) = decomp ex
              (w0', (w1', w2')) = decomp ex :: (Wrapped Int, (Wrapped Int, Wrapped Int))
           in print $ ( unwrap w, unwrap w0, unwrap $ snd w1, unwrap $ fst w1 )
         -- Also works:
         -- in print $ ( unwrap w, unwrap w0, unwrap w1 )

Мое фактическое приложение представляет собой библиотеку и будет иметь два свойства, которые делают бородавки , которые я заметил в приведенном выше:

  1. приемлемыми. конструктор типа Wrappedне экспортируется

  2. пользователь всегда будет вызывать unwrapдля всех Wrappedданных в привязке (из-за скучных деталей моего приложения ), поэтому на практике не должно быть двусмысленности

Похоже, все согласны с тем, что UndecidableInstancesне так уж и плох, но я хотел бы убедиться, что вышесказанное кошерно, прежде чем продолжить.


Обновление с решением

Я немного озадачился этим, но смог решить свою проблему с TypeFamiliesследующим образом:

{-# LANGUAGE TypeFamilies #-}
class Out a where
    type In a :: *
    decomp :: In a -> a

instance Out (Wrapped a) where
    type In (Wrapped a) = a
    decomp = Wrapped

instance (Out a, Out b)=> Out (a,b) where
    type In (a,b) = (In a,In b)
    decomp (x,y) = (decomp x, decomp y)
5
задан jberryman 6 August 2012 в 14:31
поделиться