小编Tra*_*own的帖子

通过Scala中的解析器线程化额外状态

我会给你tl; dr在前面

我想使用的状态单子转换Scalaz 7通过一个分析器,线程额外的状态,我无法做任何有用的事情而无需编写大量t m a -> t m b版本m a -> m b的方法.

解析问题的示例

假设我有一个包含嵌套括号的字符串,其中包含数字:

val input = "((617)((0)(32)))"
Run Code Online (Sandbox Code Playgroud)

我还有一个新的变量名称流(在这种情况下是字符):

val names = Stream('a' to 'z': _*)
Run Code Online (Sandbox Code Playgroud)

我想从流的顶部拉出一个名称,并在解析它时将其分配给每个括号表达式,然后将该名称映射到表示括号内容的字符串,并将嵌套的括号表达式(如果有)替换为他们的名字.

为了使这更具体,这就是我希望输出看起来像上面的示例输入:

val target = Map(
  'a' -> "617",
  'b' -> "0",
  'c' -> "32",
  'd' -> "bc",
  'e' -> "ad"
)
Run Code Online (Sandbox Code Playgroud)

在给定级别可能存在一串数字或任意多个子表达式,但这两种内容不会在单个括号表达式中混合.

为了简单起见,我们假设名称流永远不会包含重复项或数字,并且它总是包含足够的输入名称.

使用具有一些可变状态的解析器组合器

上面的示例是此Stack Overflow问题中解析问题的略微简化版本 .我用一个大致如下的解决方案回答了这个问题:

import scala.util.parsing.combinator._

class ParenParser(names: Iterator[Char]) extends RegexParsers {
  def paren: Parser[List[(Char, String)]] …
Run Code Online (Sandbox Code Playgroud)

monads haskell scala monad-transformers scalaz

26
推荐指数
1
解决办法
982
查看次数

如何使用circe解码ADT而不消除对象的歧义

假设我有这样的ADT:

sealed trait Event

case class Foo(i: Int) extends Event
case class Bar(s: String) extends Event
case class Baz(c: Char) extends Event
case class Qux(values: List[String]) extends Event
Run Code Online (Sandbox Code Playgroud)

circe中Decoder[Event]实例的默认泛型推导要求输入JSON包含一个包装器对象,该对象指示表示的是哪个case类:

scala> import io.circe.generic.auto._, io.circe.parser.decode, io.circe.syntax._
import io.circe.generic.auto._
import io.circe.parser.decode
import io.circe.syntax._

scala> decode[Event]("""{ "i": 1000 }""")
res0: Either[io.circe.Error,Event] = Left(DecodingFailure(CNil, List()))

scala> decode[Event]("""{ "Foo": { "i": 1000 }}""")
res1: Either[io.circe.Error,Event] = Right(Foo(1000))

scala> (Foo(100): Event).asJson.noSpaces
res2: String = {"Foo":{"i":100}}
Run Code Online (Sandbox Code Playgroud)

这种行为意味着如果两个或多个案例类具有相同的成员名称,我们就不必担心含糊不清,但它并不总是我们想要的 - 有时我们知道展开的编码是明确的,或者我们想要通过指定顺序来消除歧义应该尝试每个案例类,或者我们只是不在乎.

如何在Event没有包装器的情况下对ADT 进行编码和解码(最好不必从头开始编写我的编码器和解码器)?

(这个问题经常出现 - 例如今天早上 …

json scala algebraic-data-types circe generic-derivation

26
推荐指数
1
解决办法
4306
查看次数

Scala 2.10.1中的新的desugaring行为

假设我有这个monadic类:

case class Foo[A](xs: List[A]) {
  def map[B](f: A => B) = Foo(xs map f)
  def flatMap[B](f: A => Foo[B]) = Foo(xs flatMap f.andThen(_.xs))
  def withFilter(p: A => Boolean) = {
    println("Filtering!")
    Foo(xs filter p)
  }
}
Run Code Online (Sandbox Code Playgroud)

以下是2.10.0 REPL会话:

scala> for { (a, b) <- Foo(List(1 -> "x")) } yield a
res0: Foo[Int] = Foo(List(1))
Run Code Online (Sandbox Code Playgroud)

这与2.10.1中的情况相同:

scala> for { (a, b) <- Foo(List(1 -> "x")) } yield a
Filtering!
res0: Foo[Int] = Foo(List(1))
Run Code Online (Sandbox Code Playgroud)

这对我来说是完全出乎意料的,并且在过滤需要额外约束(例如Scalaz \/EitherT)的情况下会导致特别混乱的错误.

我无法在2.10.1发行说明中 …

syntax monads filtering scala for-comprehension

24
推荐指数
1
解决办法
545
查看次数

将双射提升为仿函数

也许我错过了一些明显的东西,但我正在尝试清理一个使用Scalaz 7的项目中的一些样板,而我找不到一个看似非常简单且可能有用的特殊拼图.

假设我们有两种类型的双射:

case class Foo(x: Int)
case class Bar(i: Int)

import scalaz._, Scalaz._, BijectionT._

val fb: Foo <@> Bar = bijection[Id, Id, Foo, Bar](
  foo => Bar(foo.x),
  bar => Foo(bar.i)
)
Run Code Online (Sandbox Code Playgroud)

现在假设我们发现我们需要List[Foo]和之间的双射List[Bar].我们可以轻松编写一个提供此功能的隐式类(实际上我们也可以使它适用于任何仿函数):

implicit class BijectionLifter[A, B](val bij: A <@> B) extends AnyVal {
  def liftInto[F[_]: Functor]: F[A] <@> F[B] = bijection[Id, Id, F[A], F[B]](
    _ map bij.to,
    _ map bij.from
  )
}
Run Code Online (Sandbox Code Playgroud)

请注意,这是bimapHaskell的直接翻译Data.Bijection.Scalaz的双射也有一个名为的方法bimap,但它有一个更繁忙的类型,似乎没有以任何明显的方式做我想要的.

现在我们可以写下面的内容:

fb.liftInto[List]
Run Code Online (Sandbox Code Playgroud)

我们得到了我们需要的双射.

我是否遗漏了一些抽象,这使得我可以用Scalaz 7中已经提供的用于双射的函数和实例更清晰地编写它?

scala functor bijection scalaz scalaz7

21
推荐指数
1
解决办法
569
查看次数

尝试使用Shapeless递归地将case类转换为异类列表的奇怪行为

我昨晚熬夜试图弄清楚这个无形的问题,如果我不把它从胸前拿走,我担心它会吃掉我的晚上,所以这里就是这样.

在这个最小化版本中,我只是定义了一个类型类,它将递归转换为异构列表:

import shapeless._

trait DeepHLister[R <: HList] extends DepFn1[R] { type Out <: HList }

trait LowPriorityDeepHLister {
  type Aux[R <: HList, Out0 <: HList] = DeepHLister[R] { type Out = Out0 }

  implicit def headNotCaseClassDeepHLister[H, T <: HList](implicit
    dht: DeepHLister[T]
  ): Aux[H :: T, H :: dht.Out] = new DeepHLister[H :: T] {
    type Out = H :: dht.Out
    def apply(r: H :: T) = r.head :: dht(r.tail)
  }
}

object DeepHLister extends LowPriorityDeepHLister {
  implicit …
Run Code Online (Sandbox Code Playgroud)

scala shapeless scala-macros

21
推荐指数
2
解决办法
1208
查看次数

验证与分离

假设我想编写一个带有以下签名的方法:

def parse(input: List[(String, String)]):
  ValidationNel[Throwable, List[(Int, Int)]]
Run Code Online (Sandbox Code Playgroud)

对于输入中的每对字符串,它需要验证两个成员都可以解析为整数,并且第一个成员小于第二个.然后它需要返回整数,累积任何出现的错误.

首先,我将定义一个错误类型:

import scalaz._, Scalaz._

case class InvalidSizes(x: Int, y: Int) extends Exception(
  s"Error: $x is not smaller than $y!"
)
Run Code Online (Sandbox Code Playgroud)

现在我可以按如下方式实现我的方法:

def checkParses(p: (String, String)):
  ValidationNel[NumberFormatException, (Int, Int)] =
  p.bitraverse[
    ({ type L[x] = ValidationNel[NumberFormatException, x] })#L, Int, Int
  ](
    _.parseInt.toValidationNel,
    _.parseInt.toValidationNel
  )

def checkValues(p: (Int, Int)): Validation[InvalidSizes, (Int, Int)] =
  if (p._1 >= p._2) InvalidSizes(p._1, p._2).failure else p.success

def parse(input: List[(String, String)]):
  ValidationNel[Throwable, List[(Int, Int)]] = input.traverseU(p =>
    checkParses(p).fold(_.failure, checkValues …
Run Code Online (Sandbox Code Playgroud)

validation functional-programming scala either scalaz

19
推荐指数
1
解决办法
2655
查看次数

转义Scala中Java互操作性的下划线

假设我有一些Scala代码调用一个_用作标识符的Java库(我做了 - 这是一个很长的故事).这是一个简化的例子:

public class StupidUnderscore {
  public static String _() { return "Please give me a real name!"; }
}
Run Code Online (Sandbox Code Playgroud)

没问题,对吧?逃避吧:

scala> StupidUnderscore.`_`
res0: String = Please give me a real name!
Run Code Online (Sandbox Code Playgroud)

这一直有效,直到我今天早上尝试更新到Scala 2.10.2:

scala> StupidUnderscore.`_`
<console>:1: error: wildcard invalid as backquoted identifier
       StupidUnderscore.`_`
                        ^
Run Code Online (Sandbox Code Playgroud)

这是由于2.10.1中出现的更改并修复了此问题.从提交消息:

禁止_作为标识符,它只能带来不良.

嗯,当然,但我不知道为什么这意味着我无法摆脱它 - 我认为这是反引号的意思.

我是否必须编写Java包装器才能使其工作?还有其他方法可以_在Scala中引用Java库的方法吗?


作为脚注,我已经确认可以在不编写任何新Java的情况下解决此问题:

object AwfulMacroHack {
  import scala.language.experimental.macros
  import scala.reflect.macros.Context

  def _impl(c: Context) = {
    import c.universe._
    c.Expr[String](
      Select(Ident(newTermName("StupidUnderscore")), newTermName("_")) …
Run Code Online (Sandbox Code Playgroud)

java scala

18
推荐指数
1
解决办法
1001
查看次数

来自Java代码的嵌套Scala单例

我有以下Scala(2.8)代码:

object A {
  val message = "hello"
  object B {
    val message = "world"
  }
}
Run Code Online (Sandbox Code Playgroud)

和类似的Java类:

public class C {
  public static String message() {
    return "HELLO";
  }
  public static class D {
    public static String message() {
      return "WORLD";
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

当我从Scala调用它们时,这些工作正如我所期望的那样:

scala> A.message  
res0: java.lang.String = hello

scala> A.B.message
res1: java.lang.String = world

scala> C.message  
res2: java.lang.String = HELLO

scala> C.D.message
res3: java.lang.String = WORLD
Run Code Online (Sandbox Code Playgroud)

但是当我尝试类似Java的东西时,编译器不喜欢第二行:

System.out.println(A.message());
System.out.println(A.B.message()); // cannot find ... symbol  : variable …
Run Code Online (Sandbox Code Playgroud)

java scala

16
推荐指数
1
解决办法
1059
查看次数

从非协变类的实例创建协变类型类的实例

假设我有一个简单的类型类,其实例将为我提供某种类型的值:

trait GiveMeJustA[X] { def apply(): X }
Run Code Online (Sandbox Code Playgroud)

我有一些例子:

case class Foo(s: String)
case class Bar(i: Int)

implicit object GiveMeJustAFoo extends GiveMeJustA[Foo] {
  def apply() = Foo("foo")
}

implicit object GiveMeJustABar extends GiveMeJustA[Bar] {
  def apply() = Bar(13)
}
Run Code Online (Sandbox Code Playgroud)

现在我有一个类似(但不相关)的类型类,它做同样的事情,但在其类型参数中是协变的:

trait GiveMeA[+X] { def apply(): X }
Run Code Online (Sandbox Code Playgroud)

在它的伴随对象中,我们告诉编译器如何从非协变类型类的实例创建实例:

object GiveMeA {
  implicit def fromGiveMeJustA[X](implicit giveMe: GiveMeJustA[X]): GiveMeA[X] =
    new GiveMeA[X] { def apply() = giveMe() }
}
Run Code Online (Sandbox Code Playgroud)

现在我希望implicitly[GiveMeA[Foo]]编译得很好,因为只有一种方法可以获得GiveMeA[Foo]我们在这里得到的部分.但它没有(至少不在2.10.4或2.11.2):

scala> implicitly[GiveMeA[Foo]]
<console>:16: this.GiveMeA.fromGiveMeJustA is not a valid …
Run Code Online (Sandbox Code Playgroud)

scala typeclass variance implicits subtyping

16
推荐指数
1
解决办法
655
查看次数

运行时值的精简和存在类型

假设我想在一些字符串和整数标识符之间进行映射,并且我希望我的类型使得无法获得运行时失败,因为有人试图查找超出范围的id.这是一个简单的API:

trait Vocab {
  def getId(value: String): Option[Int]
  def getValue(id: Int): Option[String] 
}
Run Code Online (Sandbox Code Playgroud)

但是,如果用户通常会从中获取ID getId并因此知道它们是有效的,那么这很烦人.以下是这种意义上的改进:

trait Vocab[Id] {
  def getId(value: String): Option[Id]
  def getValue(id: Id): String
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以这样:

class TagId private(val value: Int) extends AnyVal

object TagId {
  val tagCount: Int = 100

  def fromInt(id: Int): Option[TagId] =
    if (id >= 0 && id < tagCount) Some(new TagId(id)) else None
}
Run Code Online (Sandbox Code Playgroud)

然后我们的用户可以使用Vocab[TagId]而不必担心getValue在典型情况下检查查找是否失败,但如果需要,他们仍然可以查找任意整数.但是,它仍然很尴尬,因为我们必须为每种我们想要词汇表的东西编写一个单独的类型.

我们也可以用精致的方式做这样的事情:

import eu.timepit.refined.api.Refined
import eu.timepit.refined.numeric.Interval.ClosedOpen
import shapeless.Witness

class Vocab(values: Vector[String]) { …
Run Code Online (Sandbox Code Playgroud)

scala shapeless singleton-type refinement-type refined

16
推荐指数
1
解决办法
1324
查看次数