我有两个值,t1并且t2,类型的Either String Type.该Left-value用于错误处理.这些值用于返回的函数中Either String Type.
我想要做的是检查是否都t1和t2都Right-值和满足p :: Type -> Bool.如果他们这样做,我想回来Right (the type inside t1).如果这两个t1和t2是Right-值,但不能满足p,我要回Left someString.如果其中一个t1或是t2一个Left值,我只想传递该值.
我怎样才能以优雅的方式做到这一点?我有一种预感,使用Either作为monad是正确的做法,但我不确定如何去做.
我知道可以更改包装类型,以便您可以拥有
f :: (a -> m b)
g :: (b -> m c)
f >>= g :: (a -> m c)
Run Code Online (Sandbox Code Playgroud)
但是有可能改变m吗?如果m是MonadError,由一个实现既Either ErrorA和Either ErrorB,可不知何故,我把它们连?显然我不能直接链接它们,因为它的类型是Left什么?但是,我遇到的情况是我最后show都要打电话,但我找不到更好的解决方案
case mightFail1 of
Left e -> show e
Right v -> either show doStuff mightFail2
Run Code Online (Sandbox Code Playgroud)
在没有我必须明确检查的情况下,它无法正确使用在第一个错误处停止的monadic行为.
我有一个Web API的小型小样本应用程序,它采用了一个巨大的JSON文档,并且应该分解它并报告每个部分的错误消息.
下面的代码是使用EitherT(和错误包)的一个工作示例.但是,问题是EitherT在遇到的第一个Left上打破了计算,只返回它看到的第一个"错误".我想要的是一个错误消息列表,所有可能产生的消息.例如,如果第一行runEitherT失败,那么就没有什么可以做的了.但是如果第二行失败,那么我们仍然可以尝试运行后续行,因为它们对第二行没有数据依赖性.因此,理论上我们可以一次性生成更多(不一定是所有)错误消息.
是否可以懒惰地运行所有计算并返回我们可以找到的所有错误消息?
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Data.ByteString.Lazy.Char8 (pack)
import Web.Scotty as S
import Network.Wai.Middleware.RequestLogger
import Data.Aeson
import Data.Aeson.Types
import Control.Lens hiding ((.=), (??))
import Data.Aeson.Lens
import qualified Data.Text as T
import Control.Error
import Control.Applicative
import qualified Data.HashMap.Strict as H
import Network.HTTP.Types
data TypeOne = TypeOne T.Text TypeTwo TypeThree
deriving (Show)
data TypeTwo = TypeTwo Double
deriving (Show)
data TypeThree = TypeThree Double
deriving (Show)
main :: IO () …Run Code Online (Sandbox Code Playgroud) Either被定义为派生Show,简单地说:
data Either a b = Left a | Right b
deriving (Eq, Ord, Read, Show, Typeable)
Run Code Online (Sandbox Code Playgroud)
然而,Maybe不是:
data Maybe a = Nothing | Just a
deriving (Eq, Ord)
Run Code Online (Sandbox Code Playgroud)
既然它们是一部分base并且如此相似,为什么不Maybe直接导出Show?
另一个问题也可能是,它在哪里得到它的Show实例?
我正在玩Scala(z)学习功能编程.
我有一个类型的值,Future[List[Error \/ Double]]并希望将其转换为类型的东西Future[[List[Error] \/ List[Double]].
目标是对左派和权利进行分组.
我目前有以下内容:
val foo: Future[List[Error] \/ List[Double]] = {
for {
results <- resultsF
} yield
results.foldLeft(\/[List[Error], List[Double]])({
case (acc, v) if v.isRight => v :: \/-(acc)
case (acc, v) if v.isLeft => v :: -\/(acc)
})
}
Run Code Online (Sandbox Code Playgroud)
但是,我得到一个错误,::这是因为我的累加器不是一个列表(来自外部)\/[List[Error], List[Double]].应该怎么做?
我是C#中功能性思维方式的新手(嗯......不仅限于语言).让我们说有方法:
T LoadRecord<T>(int id)
Run Code Online (Sandbox Code Playgroud)
当给出无效输入时,我应该返回类似的内容Either<IEnumerable<ValidationError>, T>.
当调用可能抛出的DB/API/...时,我应该返回Either<Exception, T>.
因为入境可能存在,也可能不存在,我正在回归Option<T>.
如果你将上述所有内容结合起来,你最终会得到:
Either<IEnumerable<ValidationError>, Either<Exception, Option<T>> LoadRecord<T>(int id)
Run Code Online (Sandbox Code Playgroud)
我可以介绍如下类型:
Validation<T>(〜: Either<IEnumerable<ValidationError>, T>)Result<T>(〜: Either<Exception, T>)现在,我的方法的签名看起来像:
Validation<Result<Option<T>>> LoadRecord<T>(int id)
Run Code Online (Sandbox Code Playgroud)
return LoadRecord<User>(1).Match(
vl => BadRequest(),
vr => vr.Match(
el => StatusCode(500),
er => er.Some(u => Ok(u))
.None(NotFound());
Run Code Online (Sandbox Code Playgroud)
try
{
var u = LoadRecord<User>(id);
if (u == null)
{
return NotFound();
}
return Ok(u);
}
catch …Run Code Online (Sandbox Code Playgroud) 我想初始化一个Eitherto Left,但这需要指定边的类型Right(反之亦然)。
如果我不这样做,则默认情况下将Right一侧键入Nothing,以便执行以下操作:
List(5, 42, 7).foldLeft(Left("empty")) {
case (Left(_), i) => Right(i)
case (Right(s), i) => Right(s + i)
}
error: type mismatch;
found : scala.util.Right[Nothing,Int]
required: scala.util.Left[String,Nothing]
Run Code Online (Sandbox Code Playgroud)
我显然被迫冗长地提供的两面类型Either:
List(5, 42, 7).foldLeft(Left("empty"): Either[String, Int]) {
case (Left(_), i) => Right(i)
case (Right(s), i) => Right(s + i)
}
Run Code Online (Sandbox Code Playgroud)
以类似的方式,我可以使用Option.empty[Int]初始化None为Option[Int],是否可以将初始化Left("smthg")为Either[String, Int]?
我的代码结构如下例所示。我很确定应该有一种方法可以更合理地构建它。我认为 Either (or Error) monad 可以提供帮助,但我不知道从哪里开始。有什么指示可以让我朝着正确的方向前进吗?
data Data1 = Data1 { d2Id :: String }
data Data2 = Data2 { d3Id :: String }
data Data3 = Data3 { d4Id :: String }
getData1 :: String -> IO (Either String Data1)
getData2 :: String -> IO (Either String Data2)
getData3 :: String -> IO (Either String Data3)
process :: Data1 -> Data2 -> Data3 -> IO ()
get :: String -> IO ()
get id = do
r1 <- getData1 …Run Code Online (Sandbox Code Playgroud) 我想要一个将任何可迭代类型转换为C[_]的Either[A, B]函数Either[C[A], C[B]]。
我让它工作了,但我使用了asInstanceOf方法,我觉得这种方法在某些情况下可能会失败(我还不知道那会是什么场景,因为我不太了解CanBuildFrom解决)。
我认为我应该使用自定义来实现它CanBuildFrom,但我希望有更简单的方法来做到这一点。
这是我的方法:
type IterableCollection[A[_], B] = A[B] with Iterable[B]
implicit class IterableEither[C[_], A, B](self: IterableCollection[C, Either[A, B]]) {
def accumulate: Either[IterableCollection[C, A], IterableCollection[C, B]] = {
val failures = self.collect { case x @ Left(_) => x.value }.asInstanceOf[IterableCollection[C, A]]
if (failures.nonEmpty) Left(failures)
else Right(self.collect { case x @ Right(_) => x.value }.asInstanceOf[IterableCollection[C, B]])
}
}
Run Code Online (Sandbox Code Playgroud)
我已经用 Scala 编程有一段时间了,但从未依赖过asInstanceOf,因此我有点害怕将这种代码引入生产环境。你们有没有想到一种无需演员就能做到这一点的方法?
在我的Scala代码(库以及应用程序)我目前使用的混合Option和Try,当任一两个感觉更apropriate。
我倾向于实现“ doSomething”方法,该方法可以在返回值成功或在失败时成功Try。也就是说,它们可以包含引发的代码,或者当我“手动”检测到错误时,人为地创建a Throwable并返回a Failure。这些方法的返回值因此为Try[ReturnType]。
现在,我读到创建异常在某种程度上不是最优的,因为它创建了堆栈跟踪(因此很慢),而我什至不需要。我还看到了使用的子类的示例ControlThrowable,这些示例不会创建堆栈跟踪,但是它们也没有消息,Try当然也不会捕获它。
现在我的具体问题是,我一般都主张Either过Try,当我想要做的运行时错误处理/方法的返回值,并使用Try在那里我真正需要的情况下,只能抓东西(如第三方代码)?
这样,我就不必创建笨拙的Throwables,而只需使用例如字符串in Left来产生错误。
所以基本上:
Option:日常使用的东西是否具有价值Try:在方法内捕获异常,但不用作返回值Either:通用返回值,包含错误(字符串)或成功值这个概念行得通吗,还是有一种更可行/更通用的方法?