How to write a Haskell-do-notation in Scala

I wrote the following Haskell code using do-nation.

And I would like to convert it to Scala code

main :: IO ()
main = do
  print $ func1 (Right  1) (Right 2)
  print $ func1 (Right 10) (Right 3)


func1 :: Either String Int -> Either String Int -> Either String Double
func1 e1 e2 = do
  v1 <- e1
  v2 <- e2
  if v1 < v2
    then Right 1.515151  -- No meaning
    else Left  "some error"

Here is the Haskell output

Right 1.515151
Left "some error"

I wrote the Scala code as shown below. But I feel weird when I look result <- if(v1 < v2)...and yield result.

object Main {
  def main(args: Array[String]): Unit = {
    println(func1(Right(1))(Right(2)))
    println(func1(Right(10))(Right(3)))
  }

  def func1(e1: Either[String, Int])(e2: Either[String, Int]): Either[String, Double] =
    for{
      v1 <- e1
      v2 <- e2

      // Weird...
      result <- if(v1 < v2)
                  Right(1.515151)
                else
                  Left("some error")
    } yield result
}

Scala is displayed here

Right(1.515151)
Left(some error)

I would like to write below. But Scala doesn't let me write.

  // Invalid Scala Code
  def func1(e1: Either[String, Int])(e2: Either[String, Int]): Either[String, Double] =
    for{
      v1 <- e1
      v2 <- e2
    } {
      if(v1 < v2)
          Right(1.515151)
        else
          Left("some error")
    }

Could you tell me your idea to write beautifully?

+4
source share
2 answers

It may be slightly relaxed.

for {
  v1  <- e1
  v2  <- e2
  res <- Either.cond(v1 < v2, 1.515151, "some error")
} yield res

It would be nice to just drop the guard status, but according to Scala docs , this is not supported because it Eitherdoes not have a method withFilter.

+5
source

( : Haskell, , , )

Haskell do Scala for/yield , do bind (.. flatMap), for/yield map.

, Haskell, , return, Scala yield . yield - , , Haskell return. , , Haskell , Scala result <- monadicValue, yield result.

, , , Scala.


:

scalaz Either.cond(p, a, b) p.either(a).or(b), :

scala> import scalaz._, Scalaz._

scala> true.either(10).or("error")
res0: scalaz.\/[String,Int] = \/-(10)

, EitherT. :

scala> EitherT(true.either(10).or("error").some)
res1: scalaz.EitherT[Option,String,Int] = EitherT(Some(\/-(10)))
+2

Source: https://habr.com/ru/post/1682373/


All Articles