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
指定输入后,也将指定输出。其他说明1,2。
这不会阻止我们像之前一样指定更具体的实例,例如
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/