2

関数従属性の代わりに型族を使用するようにライブラリの一部を書き直しています。ただし、関数をコンパイルするために関数に追加しなければならない制約のいくつかは必要ないようです。それは私が最善の方法で物事をやっていないのではないかと私に思わせます。

Grid以下の例では、との定義を改善して、との署名をより単純にする方法はありますGridMapか?特に、制約、、およびonはエレガントではないように見えます。diffclassifyBaseGrid (Container gm k) ~ BaseGrid gmContainer (Container gm k) ~ Container gmGridMap (Container gm k)classify

{-# LANGUAGE TypeFamilies, FlexibleContexts #-}

import Prelude hiding (map)
import Data.List (minimumBy)
import qualified Data.Map as M
import Data.Ord (comparing)

class Grid g where
  type Index g
  indices :: g -> [Index g]
  -- plus other functions

class (Grid (BaseGrid gm)) => GridMap gm where
  type BaseGrid gm
  type Value gm
  type Container gm :: * -> *

  toMap :: gm -> M.Map (Index (BaseGrid gm)) (Value gm)
  toList :: gm -> [(Index (BaseGrid gm), Value gm)]
  toList = M.toList . toMap

  map
    :: (GridMap gm2, gm2 ~ Container gm (Value gm2)) => 
      (Value gm -> Value gm2) -> gm -> gm2

  mapWithKey 
    :: (GridMap gm2, gm2 ~ Container gm (Value gm2)) => 
      (Index gm -> Value gm -> Value gm2) -> gm -> gm2
  -- plus other functions

class Pattern p where
  type Metric p
  difference :: p -> p -> Metric p
  makeSimilar :: p -> Metric p -> p -> p

diff 
  :: (GridMap gm1, p ~ Value gm1, GridMap gm2, Pattern p, 
      Metric p ~ Value gm2, Container gm1 ~ Container gm2, 
      BaseGrid gm1 ~ BaseGrid gm2,
      gm2 ~ Container gm2 (Value gm2)) => 
    gm1 -> p -> gm2
diff c pattern = map (pattern `difference`) c

classify
  :: (GridMap gm, p ~ Value gm, Pattern p, Ord k, k ~ Metric p, 
      k ~ Index (BaseGrid gm), k ~ Value (Container gm k),
      BaseGrid (Container gm k) ~ BaseGrid gm,
      Container (Container gm k) ~ Container gm,
      GridMap (Container gm k)) =>
    gm -> p -> k
classify c pattern = 
  fst $ minimumBy (comparing snd) $ toList $ diff c pattern

編集:私はleventovのソリューションが好きですが、それを実装しようとすると、理解できないコンパイルエラーが発生します。

{-# LANGUAGE TypeFamilies, FlexibleContexts #-}

import Prelude hiding (map)
import Data.List (minimumBy)
import qualified Data.Map as M
import Data.Ord (comparing)

class Grid g where
  type Index g
  indices :: g -> [Index g]
  -- plus other functions

class (Grid (BaseGrid gm a)) => GridMap gm a where
  type BaseGrid gm a

  toMap :: gm -> M.Map (Index (BaseGrid gm a)) a
  toList :: gm -> [(Index (BaseGrid gm a), a)]
  toList = M.toList . toMap

  map :: GridMap gm b => (a -> b) -> gm a -> gm b -- <<<<<LINE 20>>>>>

  mapWithKey 
    :: GridMap gm b => 
      (Index (BaseGrid gm a) -> a -> b) -> gm a -> gm b
  -- plus other functions

class Pattern p where
  type Metric p
  difference :: p -> p -> Metric p
  makeSimilar :: p -> Metric p -> p -> p

diff 
  :: (GridMap gm p, Pattern p, GridMap gm m,
      Metric p ~ m, BaseGrid gm p ~ BaseGrid gm m) => 
    gm p -> p -> gm m
diff c pattern = map (pattern `difference`) c

classify
  :: (GridMap gm p, Pattern p, Ord k, k ~ Metric p, 
      k ~ Index (BaseGrid gm p),
      BaseGrid gm k ~ BaseGrid gm p) =>
    gm p -> p -> k
classify c pattern = 
  fst $ minimumBy (comparing snd) $ toList $ diff c pattern

私が得るエラーは次のとおりです。

../Amy5.hs:20:42:
    `gm' is applied to too many type arguments
    In the type `GridMap gm b => (a -> b) -> gm a -> gm b'
    In the class declaration for `GridMap'
Failed, modules loaded: none.

制約を省略した場合にも、このエラーが発生しますGridMap gm b =>

4

1 に答える 1

2

GridMapコンテナ自体と値の型の 2 つのパラメータで作成します。

何かのようなもの

{-# LANGUAGE TypeFamilies, FlexibleContexts, MultiParamTypeClasses #-}

import Prelude hiding (map)
import Data.List (minimumBy)
import qualified Data.Map as M
import Data.Ord (comparing)

class Grid g where
  type Index g
  indices :: g -> [Index g]
  -- plus other functions

class (Grid (BaseGrid gm a)) => GridMap (gm :: * -> *) a where
  type BaseGrid gm a

  toMap :: gm a -> M.Map (Index (BaseGrid gm a)) a
  toList :: gm a -> [(Index (BaseGrid gm a), a)]
  toList = M.toList . toMap

  map :: GridMap gm b => (a -> b) -> gm a -> gm b -- <<<<<LINE 20>>>>>

  mapWithKey 
    :: GridMap gm b => 
      (Index (BaseGrid gm a) -> a -> b) -> gm a -> gm b
  -- plus other functions

class Pattern p where
  type Metric p
  difference :: p -> p -> Metric p
  makeSimilar :: p -> Metric p -> p -> p

diff 
  :: (GridMap gm p, Pattern p, GridMap gm m,
      Metric p ~ m, BaseGrid gm p ~ BaseGrid gm m) => 
    gm p -> p -> gm m
diff c pattern = map (pattern `difference`) c

classify
  :: (GridMap gm p, Pattern p, Ord k, k ~ Metric p, 
      k ~ Index (BaseGrid gm p),
      GridMap gm k,
      BaseGrid gm k ~ BaseGrid gm p) =>
    gm p -> p -> k
classify c pattern = 
  fst $ minimumBy (comparing snd) $ toList $ diff c pattern
于 2013-03-04T12:44:30.583 に答える