模式匹配与无形的副产品 [英] Pattern matching with shapeless coproduct

查看:48
本文介绍了模式匹配与无形的副产品的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以对无形的副产品使用模式匹配吗?

Can I use pattern matching with shapeless coproducts?

import shapeless.{CNil, :+:}

type ListOrString = List[Int] :+: String :+: CNil

def f(a: ListOrString): Int = a match {
  case 0 :: second :: Nil => second
  case first :: Nil => first
  case Nil => -1
  case string: String => string.toInt
}

这当然行不通,因为 a 被装箱为 Coproduct.

That of course doesn't work, since a is boxed as a Coproduct.

是否有其他方法可以使用副产品并保持模式匹配的能力?

Is there an alternative way to use coproducts and maintain the ability to pattern match?

推荐答案

您可以在模式匹配中使用 InlInr 构造函数:

You can use the Inl and Inr constructors in the pattern match:

import shapeless.{ CNil, Inl, Inr, :+: }

type ListOrString = List[Int] :+: String :+: CNil

def f(a: ListOrString): Int = a match {
  case Inl(0 :: second :: Nil) => second
  case Inl(first :: Nil) => first
  case Inl(Nil) => -1
  case Inr(Inl(string)) => string.toInt
}

这种方法并不理想,因为如果您希望编译器能够判断匹配是详尽无遗的,则必须处理 CNil 情况——我们知道这种情况不可能匹配,但编译器不匹配,所以我们必须做这样的事情:

This approach isn't ideal because you have to handle the CNil case if you want the compiler to be able to tell that the match is exhaustive—we know that it's not possible for that case to match, but the compiler doesn't, so we have to do something like this:

def f(a: ListOrString): Int = a match {
  case Inl(0 :: second :: Nil) => second
  case Inl(first :: Nil) => first
  case Inl(Nil) => -1
  case Inl(other) => other.sum
  case Inr(Inl(string)) => string.toInt
  case Inr(Inr(_)) => sys.error("Impossible")
}

我个人也发现使用 InrInl 导航到联产品中的适当位置有点违反直觉.

I also personally just find navigating to the appropriate positions in the coproduct with Inr and Inl a little counterintuitive.

一般来说,最好用多态函数值折叠联积:

In general it's better to fold over the coproduct with a polymorphic function value:

object losToInt extends shapeless.Poly1 {
  implicit val atList: Case.Aux[List[Int], Int] = at {
    case 0 :: second :: Nil => second
    case first :: Nil => first
    case Nil => -1
    case other => other.sum
  }

  implicit val atString: Case.Aux[String, Int] = at(_.toInt)
}

def f(a: ListOrString): Int = a.fold(losToInt)

现在编译器将验证穷举性,而无需您处理不可能的情况.

Now the compiler will verify exhaustivity without you having to handle impossible cases.

这篇关于模式匹配与无形的副产品的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆