代表多个失败案例但只有一个成功案例的惯用类型是什么?
What’s the idiomatic type to represent multiple failure cases but only one success case?
类型 Maybe a
表示可能会失败的计算,其语义我们并不关心 如何 它失败了。如果计算成功,则可能会返回 a
类型的任何值。
相反的情况呢,计算可能由于多种原因而失败(并且我们想保留该信息)但成功不涉及除“是的,它成功了”之外的任何信息?我可以想到两种对这种计算进行编码的明显方法:
Maybe e
,其中Just e
代表失败,Nothing
代表成功。这与 Maybe
的通常用法大相径庭,我不愿意使用它。
Either e ()
,其中Left e
代表失败,Right ()
代表成功。这具有显式的优点,但具有……显式的缺点。写 ()
感觉很尴尬,尤其是在类型签名的上下文之外。
Haskell是否有更地道的方式来表示“多个失败案例,但只有一个成功案例”?
在没有看到实际代码的情况下,实际上很难理解失败的含义。如果它是一个纯函数,那么我看不出使用 Maybe
会有什么问题。我从来没有真正将 Nothing
视为失败,但就是这样:没什么。根据上下文,我要么 return Nothing as well,要么使用默认值并继续。我理解可以看做是失败,但更多的还是要看角度
如果调用者不是函数本身。
现在,您想表示一个可能会失败但 return 什么都没有的计算。如果它是一个纯函数,那没有意义。你的功能是纯粹的,什么都没有发生(没有副作用),你也没有得到结果。所以在成功的情况下,你实际上没有计算任何东西:那不是成功,那什么都不是。 ATHI 如果你失败了,你就有失败的原因。这与 returning Maybe
.
的简单检查没有什么不同
例如,您可能需要检查某个域是否在黑名单中。为此,您在列表中进行查找:没有什么意味着它很好,即使这意味着它是从您的角度来看和失败并且需要停止您的计算。相同的代码可用于检查您的域是否属于白名单。在那种情况下,没有什么是失败的:仅取决于上下文。
现在,如果你是 运行 一个单子操作(比如保存文件或其他东西),那么 return 除了可能发生不同的故障(磁盘已满,路径不正确等)之外什么都没有意义.我们不关心结果的 IO 的标准签名是 IO ()
,因此您可以选择 IO (Either e ())
(每个人都会理解)或选择 IO ()
并引发异常(如果他们真的很特别)。
从问题中不清楚计算可能会如何失败。
如果它类似于编译器,可能会产生很多错误消息(而不是在第一个错误消息时停止),那么您需要类似的东西:
type MyResult a = Either [Error] a
结果成功或失败的原因列表。
另一方面,如果您有一个不确定的计算,其中每个变化都可能成功或失败,那么您需要更像:
type MyResult a = [Either Error a]
然后搜索结果列表。如果你找到一个 Right 然后 return 它,否则 assemble Lefts 的列表。
一个简短的方法是使用 Either e ()
和 pattern synonym
pattern Success :: Either e () -- Explicit type signature not necessary
pattern Success = Right ()
你也可以包括一些其他的东西,如果它提高可读性,比如
type FailableWith e = Either e ()
pattern FailedWith :: e -> FailableWith e
pattern FailedWith x = Left x
与 Maybe
不同,Either
的优势在于所有现有机制都已经到位:Functor
、Applicative
、Monad
、Foldable
、Traversable
、Semigroup
甚至 Ord
(Left x < Right y
应该始终保持)实例可能已经完全按照您希望的错误处理方式运行。一般来说,对于这种特殊情况,Maybe
会倾向于做与你想要的相反的事情(通常你想继续成功并在第一次失败后停止,这与大多数 Maybe
机器将提供这种情况)。
类型 Maybe a
表示可能会失败的计算,其语义我们并不关心 如何 它失败了。如果计算成功,则可能会返回 a
类型的任何值。
相反的情况呢,计算可能由于多种原因而失败(并且我们想保留该信息)但成功不涉及除“是的,它成功了”之外的任何信息?我可以想到两种对这种计算进行编码的明显方法:
Maybe e
,其中Just e
代表失败,Nothing
代表成功。这与Maybe
的通常用法大相径庭,我不愿意使用它。Either e ()
,其中Left e
代表失败,Right ()
代表成功。这具有显式的优点,但具有……显式的缺点。写()
感觉很尴尬,尤其是在类型签名的上下文之外。
Haskell是否有更地道的方式来表示“多个失败案例,但只有一个成功案例”?
在没有看到实际代码的情况下,实际上很难理解失败的含义。如果它是一个纯函数,那么我看不出使用 Maybe
会有什么问题。我从来没有真正将 Nothing
视为失败,但就是这样:没什么。根据上下文,我要么 return Nothing as well,要么使用默认值并继续。我理解可以看做是失败,但更多的还是要看角度
如果调用者不是函数本身。
现在,您想表示一个可能会失败但 return 什么都没有的计算。如果它是一个纯函数,那没有意义。你的功能是纯粹的,什么都没有发生(没有副作用),你也没有得到结果。所以在成功的情况下,你实际上没有计算任何东西:那不是成功,那什么都不是。 ATHI 如果你失败了,你就有失败的原因。这与 returning Maybe
.
例如,您可能需要检查某个域是否在黑名单中。为此,您在列表中进行查找:没有什么意味着它很好,即使这意味着它是从您的角度来看和失败并且需要停止您的计算。相同的代码可用于检查您的域是否属于白名单。在那种情况下,没有什么是失败的:仅取决于上下文。
现在,如果你是 运行 一个单子操作(比如保存文件或其他东西),那么 return 除了可能发生不同的故障(磁盘已满,路径不正确等)之外什么都没有意义.我们不关心结果的 IO 的标准签名是 IO ()
,因此您可以选择 IO (Either e ())
(每个人都会理解)或选择 IO ()
并引发异常(如果他们真的很特别)。
从问题中不清楚计算可能会如何失败。
如果它类似于编译器,可能会产生很多错误消息(而不是在第一个错误消息时停止),那么您需要类似的东西:
type MyResult a = Either [Error] a
结果成功或失败的原因列表。
另一方面,如果您有一个不确定的计算,其中每个变化都可能成功或失败,那么您需要更像:
type MyResult a = [Either Error a]
然后搜索结果列表。如果你找到一个 Right 然后 return 它,否则 assemble Lefts 的列表。
一个简短的方法是使用 Either e ()
和 pattern synonym
pattern Success :: Either e () -- Explicit type signature not necessary
pattern Success = Right ()
你也可以包括一些其他的东西,如果它提高可读性,比如
type FailableWith e = Either e ()
pattern FailedWith :: e -> FailableWith e
pattern FailedWith x = Left x
与 Maybe
不同,Either
的优势在于所有现有机制都已经到位:Functor
、Applicative
、Monad
、Foldable
、Traversable
、Semigroup
甚至 Ord
(Left x < Right y
应该始终保持)实例可能已经完全按照您希望的错误处理方式运行。一般来说,对于这种特殊情况,Maybe
会倾向于做与你想要的相反的事情(通常你想继续成功并在第一次失败后停止,这与大多数 Maybe
机器将提供这种情况)。