Scala 类型构造函数作为返回类型

Scala 类型构造函数作为返回类型,scala,haskell,return-type,algebraic-data-types,type-constructor,Scala,Haskell,Return Type,Algebraic Data Types,Type Constructor,在Scala中,我可以定义: 可以返回函数f,返回类型为Maybe[a] scala> def f[A](x: A): Maybe[A] = Just(x) f: [A](x: A)Maybe[A] 但是,也可以指定只返回[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 d

在Scala中,我可以定义:

可以返回函数
f
,返回类型为
Maybe[a]

scala> def f[A](x: A): Maybe[A] = Just(x)
f: [A](x: A)Maybe[A]
但是,也可以指定只返回[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>让fx=Some x::Some Int
:10:21:
不在范围内:类型构造函数或类'Some'
该名称的数据构造函数在作用域中;你是说数据种类吗?
前奏曲>设f x=None::None

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

区别在于Scala选择如何实现ADT。Scala使用以OOP风格扩展特性的case类,因此每个case都是它自己的类型,而Haskell对于同一类型只有多个构造函数。由于它们不是单独的类型,而本质上只是单独的函数,因此无法在类型级别区分它们。有一些扩展使您能够进行类型级别的区分,但它与Scala的功能不同。尝试将Haskell的类型系统融入Scala的类型系统可能不是最好的想法


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

bhelkir和leftaroundabout已经指出了为什么不能在Haskell中精确地做到这一点:没有子类型的概念

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

import Data.Void

f :: Int -> Either Void Int
f x = Right x
Void
是一种没有定义值的类型。因此,如果您看到类型
或者Void a
,这意味着由于没有值
x::Void
任何人都无法构造形式
Left x::或者Void a
的任何值。(例外情况是
x
是保证的非终止值,但是。)

这意味着
或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

那里的
荒谬x
基本上是这样工作的:因为
x::Void
意味着
x
永远不可能有一个值,那么
荒谬x::Void->a
,根据它的类型,是一个永远无法调用的函数。类型系统的工作方式意味着它可以声明返回调用者所期望的任何类型。请参阅以获得更多讨论(尽管可能有点高级)。

有一些扩展提供了类似的功能,但Haskell没有子类化非常重要,所以你肯定不能做同样的事情。@leftaroundabout稍微改变了措辞,让它更清楚,我指的是让你在类型级别区分构造函数的扩展,但它不是Scala所拥有的。现在想清楚点了吗?也许我遗漏了什么,但为什么不直接返回
a
?我的意思是,如果排除底部,
或者Void a
a
同构。为什么要这么麻烦?
import Data.Void

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