Haskell 具有不同参数数的函数之间的统一接口
我有两个类似的功能:Haskell 具有不同参数数的函数之间的统一接口,haskell,interface,type-inference,typeclass,partial-application,Haskell,Interface,Type Inference,Typeclass,Partial Application,我有两个类似的功能: foo :: a -> b -> x -> x bar :: c -> y -> y 我想把它们统一成一个接口,这样它们就可以有相同的名称。在我的例子中,可以保证类型x和y是不同的(但可能有多个x)。所以这看起来是可能的。但在部分应用的情况下,我所有的尝试都有错误的类型推断:( 你能帮我想出这个案例的接口吗 我以前的尝试是这样的,但此解决方案需要显式类型应用程序来消除歧义: class Insert s i where insert ::
foo :: a -> b -> x -> x
bar :: c -> y -> y
我想把它们统一成一个接口,这样它们就可以有相同的名称。在我的例子中,可以保证类型x
和y
是不同的(但可能有多个x
)。所以这看起来是可能的。但在部分应用的情况下,我所有的尝试都有错误的类型推断:(
你能帮我想出这个案例的接口吗
我以前的尝试是这样的,但此解决方案需要显式类型应用程序来消除歧义:
class Insert s i where
insert :: i
instance (Ord k, i ~ (k -> Set k -> Set k)) => Insert Set i where
insert = Set.insert
我想下面的方法可能有效。根据评论,这仍然是一个糟糕、糟糕、糟糕的想法。如果你真的想这样写Haskell,那么你就不想写Haskell 无论如何,我们的想法是为以下对象提供一个类型类:
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]
请注意,类型检查器可以从列表中推断函数的类型(即使从程序中删除了foo1
),只要禁用单态限制。它将具有相当荒谬的类型:
fromList :: (Foldable t, Insert k v v, Ord k, Monoid v) => t k -> v
实际上,它可以专门用于
Ord a=>[a]->根据需要设置一个
。你能提供更多的信息吗?为什么两个签名不兼容的函数共享一个名称很重要?你在编写什么样的代码来抽象接口?@Carl我想统一这两个函数:insert::Ord k=>k->v->Map k v->Map k v
和insert::Ord a=>a->Set a->Set a
。是的,我知道这可能是个坏主意,有些人可能不喜欢。但我不会强迫任何人使用这种方法。我只关心它是否可行。这听起来不是一件有用的事情。当有可能编写有意义的代码时,你应该创建统一的接口at不在乎它使用的接口实例是什么,也不在乎名称是否相同。这在所有语言中都是如此。如果你不能互换地使用不同的实例化,你就没有抽象,这就是巧合。@Carl有可能有不同的名称,如insertMap
和insertSet
用于区分用例。但是它不太方便,因为历史上不同类型的名称都是insert
(我不认为这只是巧合,因为Set a
可能只是Map
的一个特例,就像Map a()
。但是插入()
手动。如果foo
被取消到foo::(a,b)->x->x
,那么统一foo
和bar
会更有意义。