假设我的应用有两种类型的错误:
λ: data AppError = FailedLogin | InvalidMessage deriving Show
它有login
和sendMessage
个函数:
λ: let login user pw = Left FailedLogin :: Either AppError String
λ: let sendMessage msg token = Left InvalidMessage :: Either AppError Int
λ: login "foo" "bar" >>= (\token -> sendMessage "hello world" token)
Left FailedLogin
但请注意,返回类型为Either AppError String
。我无法指定Either FailedLogin ...
:
λ: let f = Left FailedLogin :: Either FailedLogin String
<interactive>:18:36:
Not in scope: type constructor or class ‘FailedLogin’
A data constructor of that name is in scope; did you mean DataKinds?
这种行为的原因是什么,即无法在Either
的{{1}}类型中使用数据构造函数?
其次,假设我在Scala中重现了上述代码:
Left
请注意,我可以将scala> sealed trait AppError
defined trait AppError
scala> case object FailedLogin extends AppError
defined object FailedLogin
scala> case object InvalidMessage extends AppError
defined object InvalidMessage
scala> def login(user: String, password: String): Either[FailedLogin.type, String] = ???
login: (user: String, password: String)Either[FailedLogin.type,String]
指定为返回类型。如果我需要致电:FailedLogin
,那就没有意义了。但是,如果我只期望login >>= sendMessage
的{{1}}上有一个值,那么使用Either
是不是惯用的?或者是否值得创建一个具有单个子类的Left
,引用case object
s Left中的特征?
答案 0 :(得分:2)
简要说明:e
中的a
和Either e a
都需要是类型。您正在使用需要类型的值。 FailedLogin
的类型为AppError
。 AppError
构造函数中的一个是FailedLogin
。
构造函数是创建某种类型值的方法。因此,对于任何数据类型data X = A | B | C ... Z
,我们可以使用其任何构造函数来创建类型X
的值。
例如,Maybe a
是一种类型,Just
是其构造函数之一:
> :t Just 1
Just 1 :: Num a => Maybe a
Nothing
也是Maybe
的构造函数之一。
> :t Nothing
Nothing :: Maybe a
类型始终位于数据类型的左侧,而构造函数位于右侧。
我无法谈论.type
在Scala中的工作原理,但我认为在Scala中正确使用和类型只会说AppError
而不是FailedLogin
。如果FailedLogin
真正独立,它应该是它自己的特质。