代码之家  ›  专栏  ›  技术社区  ›  Shersh

不同参数个数函数之间的统一接口

  •  2
  • Shersh  · 技术社区  · 7 年前

    我有两个类似的功能:

    foo :: a -> b -> x -> x
    bar :: c -> y -> y
    

    我想把它们统一成一个接口,这样它们都可以有相同的名称。在我的情况下,它保证类型 x y 是不同的(但可能有多个 X s)。所以看起来是可能的。但我所有的尝试在部分应用的情况下都有错误的类型推断:(

    你能帮我为这个案子设计接口吗?

    我以前的尝试看起来像这样,但此解决方案需要显式类型应用程序来消除案例的歧义:

    class Insert s i where
      insert :: i
    
    instance (Ord k, i ~ (k -> Set k -> Set k)) => Insert Set i where
      insert = Set.insert
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   K. A. Buhr    7 年前

    我想以下可能行得通。根据评论,这仍然是一个可怕的,可怕的,可怕的想法。如果你真的想这样写哈斯克尔,那你就不想写哈斯克尔了。

    总之,我们的想法是为以下对象提供一个类型类:

    insert :: (Ord k) => k -> v -> a
    

    在所有三个参数中参数化,函数依赖性指定 a 确定 k v . 就你而言, a ~ (Map k' v' -> Map k' v') 暗示 k ~ k' v ~ v' ,而 a ~ Set t 暗示 k ~ t v ~ Set t .

    {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FunctionalDependencies,
                 NoMonomorphismRestriction #-}
    
    module UnifiedInsert where
    
    -- insert :: Ord k => k -> v -> Map k v -> Map k v
    -- insert :: Ord a => a -> Set a -> Set a
    
    import Data.Map (Map)
    import qualified Data.Map as Map
    import Data.Set (Set)
    import qualified Data.Set as Set
    
    class Insert k v a | a -> k, a -> v where
      insert :: (Ord k) => k -> v -> a
    instance Insert k (Set k) (Set k) where
      insert = Set.insert
    instance Insert k v (Map k v -> Map k v) where
      insert = Map.insert
    
    fromList = foldr insert mempty
    
    foo1 :: Set Int
    foo1 = fromList [1..10]
    

    注意,类型检查器可以推断函数的类型 fromList (即使 foo1 从程序中删除),只要关闭了单态限制。它将具有相当荒谬的类型:

    fromList :: (Foldable t, Insert k v v, Ord k, Monoid v) => t k -> v
    

    实际上,它可以专门用于 Ord a => [a] -> Set a ,根据需要。