2017-09-13 5 views
3

the GHC manual section on type familiesのように、カスタムインスタンスを提供することで効率的に特殊化できる「汎用」マップデータ構造が必要です。関連するデータファミリとオーバーラップするインスタンス

{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE TypeFamilies   #-} 
{-# LANGUAGE UndecidableInstances #-} 

module MapKey where 

import   Data.Map.Strict (Map) 
import qualified Data.Map.Strict as Map 

class MapKey k where 
    data MMap k :: * -> * 

instance {-# OVERLAPPING #-} MapKey() where 
    newtype MMap() v = UnitMap (Maybe v) 

instance {-# OVERLAPPABLE #-} Ord k => MapKey k where 
    newtype MMap k v = OrdMap (Map k v) 

悲しいことに、これはうまくいきません。 GHC(8.2.1)は文句を言う:

Conflicting family instance declarations: 
     MMap() = UnitMap (Maybe v) 
     MMap = OrdMap (Map k v) 
    | 
14 | newtype MMap() v = UnitMap (Maybe v) 
    | 

これにはいくつかの言語拡張機能がありますか? それ以外の場合、ユーザーがOrdの「デフォルト」インスタンスを簡単に定義できるようにする別の方法はありますか?

+0

データファミリは重複していない必要があります。タイプの安全性はもはや保持されなくなりました...興味深い考えです。 – Alec

+0

なぜそうですか?重複するメソッドだけがまだ安全である場合、関連するタイプとの重複が危険な状況がありますか? I.o.w.オーバーラップするタイプのクラスは、オーバーラップするタイプのクラスよりも「より安全ではない」場合 –

+1

関連する_type_ファミリが重複していて、_data_ファミリだけではありません。多型は重複するデータファミリで分解されます。 [ここにスケッチがあります](https://gist.github.com/harpocrates/8e9c5d693f312e39fff4c7ae1df09f41) – Alec

答えて

2

重複するインスタンスを放棄する1つの解決策は、デフォルトの関連する注入型のファミリ(かなり口一杯)を使用することです。これは、クライアントコードはまだ

instance MapKey Int 

のような定型的孤立インスタンスを定義しなければならないことを意味私はむしろ使用するソリューションを参照してくださいね

{-# LANGUAGE DefaultSignatures  #-} 
{-# LANGUAGE TypeFamilies   #-} 
{-# LANGUAGE TypeFamilyDependencies #-} 

module MapKey where 

import   Data.Map.Strict (Map) 
import qualified Data.Map.Strict as Map 

class MapKey k where 
    type MMap k v = r | r -> k v 
    type MMap k v = Map k v 
    empty :: MMap k v 
    default empty :: (MMap k v ~ Map k v) => MMap k v 
    empty = Map.empty 
    insert :: k -> v -> MMap k v -> MMap k v 
    default insert :: (MMap k v ~ Map k v, Ord k) => k -> v -> MMap k v -> MMap k v 
    insert = Map.insert 
    lookupLE :: k -> MMap k v -> [(k, v)] 
    default lookupLE :: (MMap k v ~ Map k v, Ord k) => k -> MMap k v -> [(k, v)] 
    lookupLE k m = 
    case Map.lookupLE k m of 
     Nothing -> [] 
     Just e -> [e] 

instance MapKey() where 
    type MMap() v = Maybe v 
    empty = Nothing 
    insert _ v _ = Just v 
    lookupLE _ m = 
    case m of 
     Nothing -> [] 
     (Just v) -> [((), v)] 

:私はまた、デフォルトMMap同義語のデフォルトの実装と、いくつかの方法を添付します代わりに重複するインスタンス。

関連する問題