Type Deduction如何在Haskell中运行?

时间:2009-08-29 15:32:53

标签: haskell types type-inference

我试图通过学习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。

2 个答案:

答案 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与其输入属于同一类型,并在startrate的计算中使用,并与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,...为他们定义。这就是所有的浮动手段,仅此而已。