哈斯克尔(数值)型系统
我仍然很难将我的大脑围绕在哈斯克尔及其类型系统上。
我认为
数字的
Haskell中的类型:
-
类型之间没有隐式转换(不是数字类型之间,也不是其他类型之间),因此不能隐式转换
Int
到a
Float
;
-
最
操作员在
相同的
类型例如
(+) :: Num a => a -> a -> a
,这意味着如果其中一个操作数是
内景
,则另一个操作数和结果均为
内景
s和
-
数值运算符(如
(+)
,则,
(-)
,则,
(**)
)源于
类型类别
例如
(**) :: Fractional a => a -> a -> a
源于
Fractional
类型类。
导出函数的类型(以及为什么会有问题)
现在让我们模拟Haskell编译器。定义函数:
thirdLst n x = zipWith (*) (ymod2 n) (powersOfx (fromIntegral n) x)
我们在这里看到这个函数有两个参数
n
和
x
,所以首先我们假设
thirdLst
具有类型:
thirdLst :: a -> b -> c
但我们仍然需要通过查看表达式来分析类型。我们看到
ymod2 :: Integral d => d -> [d]
(我们这里使用另一个名称,因为它们基本上是不同的变量)函数被调用,这意味着
N
是
a
以及
d
,这意味着
A.
和
D
类型相同,并且
ymod2 n
生成列表
[a]
。我们还必须添加
Integral a
类型,现在我们函数的类型是:
thirdLst :: Integral a => a -> b -> c
ymod2 n :: Integral a => [a]
我们还可以在表达式中看到
fromIntegral :: (Integral e, Num f) => e -> f
使用调用
N
作为参数,所以我们得出结论
a ~ e
(
A.
和
e
是相同的类型),并且
fromIntegral n
具有类型
Num f => f
.我们再次添加
Integral
类型约束到
A.
,但由于它已经以这种方式受到约束
A.
保持不变:
thirdLst :: Integral a => a -> b -> c
ymod2 n :: Integral a => [a]
fromIntegral n :: Num f => f
这个
fromIntegral
表达式只是的子表达式
(powersOfx (fromIntegral n) x)
自从
powersOfx
具有类型
powersOfx :: (Enum g, Floating g) => g -> g -> [g]
.因此,我们知道
f ~ g
和
b ~ g
,因此我们知道表达式的结果是
[b]
,我们必须添加
Enum b
和
Floating b
作为约束:
thirdLst :: (Integral a, Enum b, Floating b) => a -> b -> c
ymod2 n :: Integral a => [a]
fromIntegral n :: Num b => b
powersOfx (fromIntegral n) x :: (Enum b, Floating b) => [b]
这到目前为止没有问题,这两个参数
第三名
,则,
N
和
十、
有不同的类型,但现在我们使用
zipWith :: (h -> i -> j) -> [h] -> [i] -> [j]
我们使用作为第一个参数
(*) :: Num k => k -> k -> k
,因此我们知道
k ~ h ~ i ~ j
因此
zipWith (*)
具有类型:
zipWith (*) :: Num k => [k] -> [k] -> [k]
现在问题来了,我们看到
zipWith(*)
需要有
相同的
类型自从
ymod2 n :: Integral a => [a]
和
powersOfx (fromIntegral n) x :: (Enum b, Floating b) => [b]
是我们用于
zipWith(*)
这意味着
k ~ a ~ b
所以
k
,则,
A.
和
b
都是相同的类型。现在我们得出结论:
thirdLst :: (Integral a, Enum a, Floating a, Num a) => a -> a -> [a]
这意味着这两个参数需要具有相同的类型。现在这已经导致了一个重要问题:数字通常不是
完整的
和
Floating
同时在最常见的数字库中,没有两种数字类型
浮动
和
完整的
同时因此,这使得该函数非常无用。
允许更多自由
因此,我们需要找到更多的泛型函数和更多的自由度。你的
功率OFX
函数为
也
限制性:由于列表的长度
十、
需要具有相同的类型。我们可以在两种类型独立的情况下构建一个:
import Data.List(genericTake)
powersOfx :: (Num a, Integral i) => i -> a -> [a]
powersOfx n x = genericTake (n+1) (iterate (x*) 1)
对于
ymod2
,您基本上构建了一个具有特定长度的列表
[0, 1, 0, 1, ...]
.所以我们可以使用
cycle :: [a] -> [a]
为了这个,还有一个
genericTake (n+1)
:
ymod2 :: (Num a, Integral i) => i -> [a]
ymod2 n = genericTake (n+1) (cycle [0, 1])
然后我们的功能是:
thirdLst :: (Num c, Integral a) => a -> c -> [c]
thirdLst n x = zipWith (*) (ymod2 n) (powersOfx n x)