我试图通过学习Haskell来拓宽思路。
我自己造成的功课是建立一个时钟滴答发生器,它会给我泊松分布的间隔,最终结果(经过长时间的斗争,我承认)是这样的:
import System.Random
poissonStream :: ( Ord r, Random r, Floating r, RandomGen g) => r -> r -> r -> g -> [r]
poissonStream rate start limit gen
| next > limit = []
| otherwise = next:(poissonStream rate next limit newGen)
where (rvalue, newGen) = random gen
next = start - log(rvalue) / rate
但有两件事(至少)我不明白:
为什么我需要“Ord r
”以及“Floating r
”? (我本来期望某种自动继承:“浮动”意味着“Ord”。)
隐含的类型定义“rvalue :: Float
”实现了什么路径?
在GHCi中,我得到了我的预期:
*Main System.Random> let (rvalue, newGen) = random (mkStdGen 100)
<interactive>:1:23:
Ambiguous type variable `t' in the constraint:
`Random t' arising from a use of `random' at <interactive>:1:23-43
Probable fix: add a type signature that fixes these type variable(s)
rvalue 是一个松散的大炮,我必须绑定:
*Main System.Random> let (rvalue, newGen) = random (mkStdGen 100) :: (Float, StdGen)
*Main System.Random> rvalue
0.18520793
请温柔地使用Haskell n00b。
答案 0 :(得分:12)
为什么我需要“Ord r”以及“Floating r”? (我本来期望某种自动继承:“浮动”意味着“Ord”。)
Floating
应该对所有浮点数进行分类,包括复数浮点数。没有复杂数字的排序。您可以使用RealFloat
代替Floating
,这意味着Ord
。
通过什么路径隐含的类型定义“rvalue :: Float”实现了?
您可以从使用rvalue
的上下文中推断出来。这是log
和
:t log
给出
log :: (Floating a) => a -> a
因此rvalue
必须位于Floating
类中(因此它将是“Floating
类型类中的某种类型,而不是Float
类。”此外,结果为log
与其输入属于同一类型,并在start
和rate
的计算中使用,并与limit
进行比较,所有类型均为r
,因此rvalue
属于r
(这是合适的,因为r
也属于Floating
。
在GHCi示例中,没有更多上下文。型
:t random (mkStdGen 100)
这会给你
random (mkStdGen 100) :: (Random a) => (a, StdGen)
GHCi不知道此处为a
填写的类型。它只知道它必须在类型Random
中。
答案 1 :(得分:2)
在Haskell中,Ord和Floating是独立的或orthogonal概念。也许你假设Floating只引用了非常具体的类型,比如Double和Float(大多数其他语言就是这种情况)?
正如Rudiger所指出的,有些类型是浮点类的实例,它们不是Ord,因为某些浮点类型没有排序,比如Complex。除了复数之外的另一个例子是向量,你可以为它们定义这些浮动函数,但不能定义任何合理的Ord-ering。
请记住,类型类只是指定一组函数(如Java或C#中的接口,如果这是一种有用的思考方式),必须为类型 a 定义;要成为Ord,类型 a 只需要比较运算符,并且作为Floating的实例,类型 a 只需要实现Fractional并具有函数pi,exp, sqrt,log,sin,cos,...为他们定义。这就是所有的浮动手段,仅此而已。