【问题标题】:Type Constructor as Return Type类型构造函数作为返回类型
【发布时间】:2015-06-03 14:53:05
【问题描述】:

在 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 中,类型构造函数不能是返回类型?

【问题讨论】:

    标签: scala haskell return-type algebraic-data-types type-constructor


    【解决方案1】:

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

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

    【讨论】:

    • 有一些扩展可以为你提供类似的能力,但是Haskell没有子类化是非常重要的,所以你肯定不能做同样的事情..
    • @leftaroundabout 稍微更改了措辞以更清楚地表明我指的是可以让您在类型级别区分构造函数的扩展,但这不是 Scala 所具有的。认为它现在更清楚了吗?
    【解决方案2】:

    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 -&gt; a,给定它的类型,是一个永远不可能调用的函数.类型系统的工作方式意味着它可以声称返回调用者期望的任何类型。更多讨论请参见this question(虽然可能有点高级)。

    【讨论】:

    • 也许我遗漏了什么,但为什么不直接返回a
    • 我的意思是,如果你排除底部,Either Void aa 同构。为什么要这么麻烦?
    猜你喜欢
    • 2020-08-19
    • 1970-01-01
    • 2019-09-03
    • 2015-07-08
    • 1970-01-01
    • 1970-01-01
    • 2019-05-04
    • 2020-09-10
    • 1970-01-01
    相关资源
    最近更新 更多