Haskell 使用类型族时简化类型签名?
我正在重写一些库,以使用类型族而不是函数依赖项。然而,为了使函数能够编译,我必须添加到函数中的一些约束似乎是不必要的。这让我怀疑我没有以最好的方式做事 在下面的示例中,是否有方法改进Haskell 使用类型族时简化类型签名?,haskell,type-families,Haskell,Type Families,我正在重写一些库,以使用类型族而不是函数依赖项。然而,为了使函数能够编译,我必须添加到函数中的一些约束似乎是不必要的。这让我怀疑我没有以最好的方式做事 在下面的示例中,是否有方法改进Grid和GridMap的定义,以便diff和classify的签名更简单?特别是,BaseGrid(Container gm k)~BaseGrid gm、Container(Container gm k)~Container gm和GridMap(Container gm k)对classify的约束似乎不雅观
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
编辑:我喜欢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
如果我取消约束
GridMap gm b=>
我也会得到这个错误,我将使用两个参数制作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
{-#语言类型族、灵活上下文、多段类型类#-}
导入前奏隐藏(地图)
导入数据列表(最小值)
导入符合条件的数据。映射为M
导入数据。Ord(比较)
g类网格,其中
类型索引g
索引::g->[索引g]
--加上其他功能
类(Grid(BaseGrid gm a))=>GridMap(gm::*->*)a其中
基本网格类型gm a
toMap::gm a->M.Map(索引(基本网格gm a))a
toList::gm a->[(索引(基本网格gm a),a)]
托利斯特=M.托利斯特。托马普
地图::网格地图gm b=>(a->b)->gm a->gm b--
mapWithKey
::GridMap gm b=>
(索引(基本网格gm a)->a->b)->gm a->gm b
--加上其他功能
类模式p在哪里
类型度量p
差异::p->p->度量值p
makesimular::p->Metric p->p->p
差异
::(GridMap gm p,模式p,GridMap gm m,
度量p~m,BaseGrid gm p~BaseGrid gm m)=>
总经理p->p->m总经理
diff c pattern=map(pattern`difference`)c
分类
:(网格图gm p,模式p,Ord k,k~度量p,
k~指数(基本网格gm p),
GridMap gm k,
BaseGrid gm k~ BaseGrid gm p)=>
总经理p->p->k
分类c模式=
fst$minimumBy(比较snd)$toList$diff c模式
这不是完全等效的转换。您的变体解除了gm
上a
的隐式函数依赖关系,而在原始版本中,此依赖关系是通过关联类型建模的。@Vladimir Matveev为什么gm
与原始容器类似,属于*->*
?对不起,我确信它只是*
。是我的错。你完全正确。我喜欢这个解决方案,但我在编译时遇到了麻烦。我已经编辑了上面的问题。@mhwombat我已经编辑了答案,为gm
添加了明确的数据类型签名。现在它正在为我编译。
{-# 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