haskell如何'向下'一个类型界面?

时间:2013-08-12 10:28:59

标签: haskell types downcast

在oop中,例如java,当类型实际上是子类时,我们只能将超级类转发为子类

但是在haskell中,我们可以简单地将一个类型“转发”到该类型类的任何实例中。例如返回fromInteger的{​​{1}}。从我的观点来看,它实际上是一个 Int 所以它不能被“下载”到 Float ,但它可以。

Num

另一个例子是将Prelude System.Random> :t fromInteger a fromInteger a :: Num a => a Prelude System.Random> fromInteger 12 :: Int 12 Prelude System.Random> fromInteger 12 :: Float 12.0 更改为Int,Float甚至Bool

Random

我们不知道Random实际上是什么,但我们可以将它“转发”为实例的类型,并且它始终100%工作。我不明白为什么会这样。

3 个答案:

答案 0 :(得分:9)

我认为您错误地将类型类视为OO类并将类型继承与它们相关联而感到困惑。类型类非常不同,Haskell中没有类型继承,顺便说一句,它根本就不是一个弱点。你的例子实际上展示了很多Haskell的力量。

让我们分析一下random的定义:

random :: RandomGen g => g -> (a, g)

它有一个签名g -> (a, g),表示它需要一些值g并返回一些值a和一些与输入g相同类型的值,此签名中未指定IntChar等特定类型,agpolymorphic,这意味着它们可以是任何类型。接下来是约束部分RandomGen g =>,它表示实际上g只能是一个具有类型类RandomGen实例的类型,就在我链接的类的接口下面你会找到模块中定义的实例列表,它只包含RandomGen StdGen,所以基本上我们可以看到gStdGen。然后再看一下random函数,找出它实际上被定义为类型类Random的接口的一部分,它由类型变量a参数化,我们已经已经在函数random的签名中遇到,因此这意味着对函数Random a的定义有random约束。另请参阅其实例列表中的此类包含Random IntRandom DoubleRandom Bool

现在让我们回到你的例子。通过指定类型random (mkStdGen 12) :: (Bool, StdGen),您告诉编译器将random视为random :: StdGen -> (Bool, StdGen),从中简单推导出RandomGenRandom的实例使用。这些实例实际上定义了函数的类型特定行为,这反过来保证任何可编译的代码都有意义。

如你所见,这一切与铸造完全无关。

答案 1 :(得分:2)

  

从我的角度来看,它实际上是一个Int

这是你错的地方。 fromInteger有两种不同的实现:Integer -> IntInteger -> FloatInt绝对没有fromInteger 12 :: Float

答案 2 :(得分:1)

从@MikeHartl的注释中可以看出,Haskell类型类不是OOP意义上的类。它们也不是接口。在您的情况下,将它们视为所有方法为静态的C ++模板类可能很有用:

template <typename T>
class Random
{
public:
   static std::pair<T, StdGen> random(StdGen a);
}

“cast”根本不是“强制转换”,而是模板参数的明确限定:

std::pair<Int, StdGen> a = Random<Int>::random(mkStdGen 12);
std::pair<Int, Bool> a = Random<Bool>::random(mkStdGen 12);

同样适用于Num

template <typename a>
class Num
{
public:
   static a fromInteger(Integer b);
}

int a = Num<int>::fromInteger(Integer(2222));
complex a = Num<complex>::fromInteger(Integer(3333));