我有以下类型签名:
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void add(..){..}
当我询问结果类型时:
let kessel :: (Ord a, Num b) => a -> b -> a; kessel = undefined
我有:
:t kessel 1 2
为什么不kessel 1 2 :: (Num a, Ord a) => a
?
答案 0 :(得分:9)
因为1
的类型为Num a => a
:
ghci> :t 1
1 :: Num a => a
ghci> :t kessel
kessel :: (Num b, Ord a) => a -> b -> a
ghci> :t kessel 1
kessel 1 :: (Num a, Num b, Ord a) => b -> a
ghci> :t kessel 1 2
kessel 1 2 :: (Num a, Ord a) => a
来自1
(Num
)的约束将添加添加到已存在的。例如,使用id
时,情况相同:
id :: a -> a
id 1 :: Num a => a
当您使用kessel :: (Ord a, Num b) => a -> (b -> a)
时,您告诉编译器kessel
将任何 a
,即Ord
的实例。然后,kessel
将从任何其他(不一定是不同的)类型b
返回一个函数,该函数也是前面提到的类型{Num
的一个实例。 1}}。
这意味着您用于a
的第一个参数将设置kessel
:
a
在所有这些情况下,论证的类型都很清楚。但是,如果我们使用多态的值呢?例如这一个:
ghci> :t kessel (1 :: Int)
kessel (1 :: Int) :: Num b => b -> Int
ghci> :t kessel 'A'
kessel 'A' :: Num b => b -> Char
ghci> :t kessel "Hello, World!"
kessel "Hello, World!" :: Num b => b -> String
并让我们使用更简单的功能,即magic :: Magic a => a
:
const
什么是const :: a -> b -> a
const x y = x
?让我们开始更简单。什么是const magic
?
const "Hello, World?"
我们用const :: a -> b -> a
"Hello, World?" :: String
const "Hello, World?" :: b -> String
类型替换了 a
的每个出现。现在回到我们的"Hello, World?"
示例:
magic
同样,我们会将const :: a -> b -> a
magic :: Magic t => t
const magic :: Magic t => b -> t
的每一个匹配项替换为我们的类型,在本例中为a
。但是,我们不能忘记对t
的额外限制,即t
。我们必须把它带来。因此,我们在这里获得了额外的约束。但如果对Magic
有任何限制,我们仍需将其置于a
。
现在让我们回到原来的t
:
kessel
我们仍保留kessel :: (Num b, Ord a ) => a -> b -> a
1 :: (Num n ) => n
kessel 1 :: (Num na, Ord na, Num b) => b -> na
的原始约束。因此,我们现在有两个约束,a
和Num
。如果我们现在使用任何满足Ord
约束的类型,我们剩下的就是Num
。由于它不再在右侧,因此可以放弃其约束:
na