[英]Type Constructor as Return Type
In Scala, I can define an Algebraic Data Type :在 Scala 中,我可以定义一个代数数据类型:
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
It's possible to return a function, f
, with a return type of Maybe[A]
.可以返回返回类型为Maybe[A]
的函数f
。
scala> def f[A](x: A): Maybe[A] = Just(x)
f: [A](x: A)Maybe[A]
However, it's also possible to specify that a Just[A]
is returned.但是,也可以指定返回Just[A]
。
scala> def f[A](x: A): Just[A] = Just(x)
f: [A](x: A)Just[A]
Now I'll do the similar exercise in Haskell:现在我将在 Haskell 中做类似的练习:
Prelude> data Option a = None | Some a deriving Show
Prelude> let f x = Some x :: Option Int
Prelude> f 10
Some 10
But, I can't set a return type of a type constructor .但是,我无法设置类型构造函数的返回类型。
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
Is the simple difference that Scala's Just
is a class, ie a legitimate return type? Scala 的Just
是一个类,即合法的返回类型,这是一个简单的区别吗? Whereas, in Haskell, a type constructor cannot be a return type?而在 Haskell 中,类型构造函数不能是返回类型?
The difference is how Scala chose to implement ADTs.不同之处在于 Scala 选择实现 ADT 的方式。 Scala uses case classes that extend a trait in an OOP style, so each case is its own type, whereas Haskell just has multiple constructors for the same type. Scala 使用 case 类以 OOP 风格扩展特征,因此每个 case 都是它自己的类型,而 Haskell 只具有相同类型的多个构造函数。 Since they aren't separate types but essentially just separate functions, you can't distinguish them at the type level.由于它们不是单独的类型,而本质上只是单独的函数,因此您无法在类型级别区分它们。 There are extensions that give you some ability to make that type level distinction, but it won't be the same thing as what Scala has.有一些扩展可以让您进行类型级别的区分,但它与 Scala 所拥有的不同。 And trying to fit Haskell's type system into Scala's type system is probably not the best of ideas.尝试将 Haskell 的类型系统融入 Scala 的类型系统可能不是最好的主意。
In short, Scala approximates ADTs using a form of inheritance, whereas Haskell just has ADTs.简而言之,Scala 使用继承的形式来近似 ADT,而 Haskell 只有 ADT。
bhelkir and leftaroundabout have pointed out why you can't do this exactly in Haskell: there is no notion of subtypes. bhelkir 和 leftaroundabout 已经指出为什么你不能在 Haskell 中做到这一点:没有子类型的概念。
But note that with ADTs there are often alternatives that allow you achieve the same effect.但请注意,使用 ADT 时,通常有其他替代方案可以让您达到相同的效果。 In this case, one candidate technique would be to use the Void
type in conjunction with Either
:在这种情况下,一种候选技术是将Void
类型与Either
结合Either
:
import Data.Void
f :: Int -> Either Void Int
f x = Right x
Void
is a type that has no defined values. Void
是一种没有定义值的类型。 Therefore if you see the type Either Void a
, that means that since there's no value x :: Void
nobody can ever construct any value of the form Left x :: Either Void a
.因此,如果您看到Either Void a
类型,则意味着由于没有值x :: Void
没有人可以构造Left x :: Either Void a
形式的任何值。 (The exception is if x
is a guaranteed nonterminating value, but we customarily ignore that possibility .) (例外情况是如果x
是一个有保证的非终止值,但我们通常会忽略这种可能性。)
That means that an Either Void a
is always of the form Right a
, so for example, you can write this function:这意味着“ 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
The absurd x
there works basically like this: since x :: Void
that means that there can never actually be a value for x
, then absurd :: Void -> a
, given its type, is a function that is impossible to ever call.该absurd x
那里的工作基本上是这样的:因为x :: Void
即意味着永远实际上是一个值x
,那么absurd :: Void -> a
,因为它的类型,是一个函数,是不可能永远电话。 The way the type system works this means that it can claim to return any type at all that the caller expects.类型系统的工作方式意味着它可以声称返回调用者期望的任何类型。 See this question for some more discussion (though maybe a bit advanced).请参阅此问题以进行更多讨论(尽管可能有点高级)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.