键入构造函数作为返回类型

时间:2015-06-03 14:53:05

标签: scala haskell

在Scala中,我可以定义Algebraic Data Type

scala> sealed trait Maybe[A]
defined trait Maybe

scala> case class Just[A](x: A) extends Maybe[A]
defined class Just

scala> case object NothingHere extends Maybe[Nothing]
defined object NothingHere

可以返回功能f,返回类型为Maybe[A]

scala> def f[A](x: A): Maybe[A] = Just(x)
f: [A](x: A)Maybe[A]

但是,也可以指定返回Just[A]

scala> def f[A](x: A): Just[A] = Just(x)
f: [A](x: A)Just[A]

现在,我将在Haskell中进行类似的练习:

Prelude> data Option a = None | Some a deriving Show
Prelude> let f x = Some x :: Option Int
Prelude> f 10
Some 10

但是,我无法设置类型构造函数的返回类型

Prelude> let f x = Some x :: Some Int

<interactive>:10:21:
    Not in scope: type constructor or class `Some'
    A data constructor of that name is in scope; did you mean DataKinds?
Prelude> let f x = None :: None

Scala的Just是一个类,即合法的返回类型,这是一个简单的区别吗?然而,在Haskell中,类型构造函数不能是返回类型?

2 个答案:

答案 0 :(得分:10)

不同之处在于Scala如何选择实施ADT。 Scala使用以OOP样式扩展特征的case类,因此每个case都是它自己的类型,而Haskell只有多个相同类型的构造函数。由于它们不是单独的类型,而是基本上只是单独的函数,因此您无法在类型级别区分它们。有一些扩展可以让你有一些能够进行类型级别区分的扩展,但它与Scala所具有的不同。尝试将Haskell的类型系统融入Scala的类型系统可能不是最好的想法。

简而言之,Scala使用一种继承形式来近似ADT,而Haskell只有ADT。

答案 1 :(得分:0)

bhelkir和leftaroundabout指出了为什么你不能在Haskell中完全做到这一点:没有子类型的概念。

但请注意,对于ADT,通常有替代方案可以实现相同的效果。在这种情况下,一种候选技术是将the Void typeEither结合使用:

import Data.Void

f :: Int -> Either Void Int
f x = Right x

Void是一种没有定义值的类型。因此,如果您看到类型Either Void a,则表示由于没有值x :: Void,任何人都无法构造Left x :: Either Void a形式的任何值。 (例外情况是x是保证的非终止值,但是we customarily ignore that possibility。)

这意味着Either Void a始终采用Right a形式,例如,您可以编写此函数:

-- | Extract the @a@ from @Either Void a@.
extract :: Either Void a -> a
extract (Left x) = absurd x
extract (Right a) = a

absurd x基本上是这样的:因为x :: Void表示实际上永远不会有x的值,所以absurd :: Void -> a给定其类型,是一个不可能打电话的功能。类型系统的工作方式意味着它可以声称返回调用者期望的任何类型。有关更多讨论,请参阅this question。(尽管可能有点高级)。