我正在重写我的一些库以使用类型系列而不是函数依赖项。但是,似乎我必须添加到函数中的一些约束才能使它们进行编译。这让我怀疑我没有以最好的方式做事。
在下面的示例中,有没有办法改进Grid
和GridMap
的定义,以便diff
和classify
的签名更简单?特别是,BaseGrid (Container gm k) ~ BaseGrid gm
上的约束Container (Container gm k) ~ Container gm
,GridMap (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
{-# 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 =>
,我也会收到此错误。
答案 0 :(得分:2)
我会使用{2}参数创建GridMap
:容器本身和值类型。
像
这样的东西{-# 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