Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 具有不同参数数的函数之间的统一接口_Haskell_Interface_Type Inference_Typeclass_Partial Application - Fatal编程技术网

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
会更有意义。