This answer演示了一个多变量函数,该函数将其参数求和:

class SumRes r where
    sumOf :: Integer -> r

instance SumRes Integer where
    sumOf = id

instance (Integral a, SumRes r) => SumRes (a -> r) where
    sumOf x = sumOf . (x +) . toInteger
我为Num的所有成员创建了此函数的通用版本:
class (Num n) => MySumType n r where
    mySum :: n -> r

instance (Num n) => MySumType n n where
    mySum x = x

instance (Num n, MySumType n r) => MySumType n (n->r) where
    mySum x = mySum . (x +)
但是,这仅适用于mySum (1::Int) (3::Int) (2::Int) :: Int之类的调用。如果在参数上没有类型说明符,则会出现此错误:

是什么导致此问题,我该如何解决?我怀疑这与整数文字类型Num a => a有关。还有上面不依赖扩展的等效功能吗?上面使用的是多个参数类型类和灵活实例。

最佳答案

到目前为止,我还没有在haskell中遇到过引人注目的多变量函数用例,这不能通过使用列表或类似的数据结构来解决。因此,如果您认为自己具有新颖性,我与他们一起玩耍的原因,那么我将很高兴知道它的含义。下面提供了足够的示例,我在撤消发言时应该考虑其中的一些示例,我在发表评论时应该考虑这些示例。

{-# language MultiParamTypeClasses #-}
{-# language FlexibleInstances #-}
{-# language TypeFamilies #-}
{-# language IncoherentInstances #-}

class (Num n) => MySumType n r where
    mySum :: n -> r

instance (Num n, m~n) => MySumType n m where
    mySum x = x

instance (Num n, MySumType n r, n~m) => MySumType n (m->r) where
    mySum x = mySum . (x +)

然后将文件加载到ghci中:
> mySum 1 2 4 5 6 7 :: Int
25
> mySum 1.1 2 4.6 5 6.9 7 :: Double
26.6

在某些情况下,类型推断也可以成为您的 friend ,允许您删除最终类型注释,例如在以下人为情况下:
> replicate (mySum 1 2 3 4) 6
[6,6,6,6,6,6,6,6,6,6]

关于:



我觉得你不走运。我想指出的是,除非您有理由离开GHC或继续使用Haskell98或Haskell2010,否则扩展不会对您造成任何损害,也不会造成兼容性问题,因为大多数人似乎仍在使用GHC。

编辑:附加说明

让我们开始解释一下简单实例之间的区别。我将在我提供的一些实现名称中添加postfix 2。
instance (Num n) => MySumType n n where
    mySum x = x

如果将此与类声明结合使用:
class (Num n) => MySumType n r where
    mySum :: n -> r
mySum的类型签名为mySum :: (Num n) => n -> n。该n -> n表示一个类型为1的arity函数,其类型为n,生成n,而n具有Num类。

使用此mySum时,我必须指定给出的内容和产生的内容。
mySum 1 :: Int
mySum (1 :: Int)

仅当指定了输入和输出类型时,它们都将给出错误,并且将给出结果:
mySum (1 :: Int) :: Int
            ^       ^
            |       specify output type
            specify input type

产生一个结果(在这种情况下为1)。这是因为您已经为n -> n给出了一个实例,但是有些人以后可以为n -> m添加一个实例,例如Int -> Double,如下所示:
instance MySumType Int Double where
    mySum x = 2 * fromIntegral x

> mySum (1::Int) :: Int
1
> mySum (1::Int) :: Double
2.0

这些实例分别与所有1种arity函数类型的非常狭窄的范围相匹配。

现在让我们看一下修改后的版本
instance (Num n, m~n) => MySumType n m where
    mySum x = x

此处的mySum具有类型签名mySum :: (Num n, m~n) => n -> m,该类型签名针对所有1个使用n类型并产生m类型的arity函数表示,其中n具有Num类,并且m等于n。请注意,这开始是将​​所有1个arity函数n -> m,任何n与任何m匹配,然后在其上放置约束。

现在可以执行以下操作:
> mySum2 (1::Int)
1
> mySum2 1 :: Int
1

指定输入后,也将指定输出。其他说明12

这不会阻止我们像之前一样指定更具体的实例,例如Int -> Double:
instance MySumType Int Double where
    mySum x = 2 * fromIntegral x

> mySum2 1 :: Int
1
> mySum2 1 :: Double
1.0
> mySum2 (1 :: Int) :: Double
2.0

只有最后一个mySum2正在处理Int -> Double实例。这是IncoherentInstances的属性,我想我将其留给another stackoverflow question来回答IncoherentInstances扮演的角色。

关于haskell - 多元广义和,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16307399/

10-13 02:19