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