Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 由作用于余积的单态函数得到的多函数_Scala_Shapeless - Fatal编程技术网

Scala 由作用于余积的单态函数得到的多函数

Scala 由作用于余积的单态函数得到的多函数,scala,shapeless,Scala,Shapeless,我正在开发一个API,它应该能够从标准的单态函数动态地构建一个不成形的Poly1函数,这些函数在某些副产品的类型上运行 目标是公开一个接收函数的简单方法,如下所示: type FooCoproduct = Foo :+: Bar :+: CNil def addF[E](f: E => E)(implicit ev: Inject[FooCoproduct, E]) = ??? 并累加这些函数,以构建一个覆盖副产品中所有类型的总Poly1函数。这里的证据是要强制类型参数E是副产品中的一种

我正在开发一个API,它应该能够从标准的单态函数动态地构建一个不成形的
Poly1
函数,这些函数在某些副产品的类型上运行

目标是公开一个接收函数的简单方法,如下所示:

type FooCoproduct = Foo :+: Bar :+: CNil
def addF[E](f: E => E)(implicit ev: Inject[FooCoproduct, E]) = ???
并累加这些函数,以构建一个覆盖副产品中所有类型的总Poly1函数。这里的证据是要强制类型参数
E
是副产品中的一种类型

在测试了几种方法(包括类型类的泛型派生)之后,最有希望的一种方法使我在
HList
中积累了这些单态函数,并尝试通过
选择器来解析适用的方法。通过示例可能更好地理解这一点:

object CoproductSample extends App {

  import shapeless.{ :+:, CNil, Coproduct, HList, HNil, Poly1 }
  import shapeless.ops.coproduct.Inject
  import shapeless.ops.hlist.Selector

  class Builder[A <: Coproduct] {

    def accum[B](f: B => B, hl: HList)(implicit ev: Inject[A, B]) = f :: hl

    class PolyBuilder[L <: HList](hl: L) extends Poly1 {
      implicit def run[T](implicit ev: Selector[L, T => T]) = 
        at[T](hl.select[T => T])
    }

  }

  type Cop = Int :+: String :+: CNil

  val builder = new Builder[Cop]

  val hl1 = builder.accum((i: Int) => i + 1, HNil)
  val hl2 = builder.accum((s: String) => s + "one", hl1)

  object pf extends builder.PolyBuilder(hl2)

  val rInt = Coproduct[Cop](10).fold(pf)
  val rStr = Coproduct[Cop]("ten").fold(pf)
}
我想我需要提供一个
选择器[L,T=>T]
,其中
L
是累加
HList
的类型,但我想不出方法。另一方面,我觉得必须有一个更简单的办法来解决我的问题

任何帮助都将不胜感激

更新

在做了更多的研究之后,我想出了一个几乎可行的解决方案。不幸的是,我无法正确跟踪结果类型

object CoproductSample {
  import shapeless.{ CNil, Coproduct, HList, HNil, Inl, Inr, Poly2, ::, :+: }

  // Accumulates ordinary functions from A => A in an HList
  def accum[A, L <: HList](f: A => A, hl: L): (A => A) :: L = f :: hl

  // A poly2 function that evaluates some monomorphic function present in
  // an HList for certain value that satifies the signature of this function
  object PolyEval extends Poly2 {
    implicit def hnilCase[A]: Case.Aux[A, HNil, Option[A]] =
      at[A, HNil]((a, l) => None)

    implicit def hheadCaseSuccess[A, T <: HList]: Case.Aux[A, (A => A) :: T, Option[A]] =
      at[A, (A => A) :: T]((a: A, l: (A => A) :: T) => Option(l.head(a)))

    implicit def hheadCaseFail[A, H, T <: HList](
        implicit tail: Case.Aux[A, T, Option[A]]
    ): Case.Aux[A, (H => H) :: T, Option[A]] =
      at[A, (H => H) :: T]((a: A, l: (H => H) :: T) => PolyEval(a, l.tail))
  }

  // A poly2 function that uses `PolyEval` for evaluating a value present in
  // a coproduct against an HList of monomorphic functions
  object PolyEvalCop extends Poly2 {
    implicit def cnilCase[A <: CNil, L <: HList]: Case.Aux[A, L, Option[A]] =
      at[A, L]((a, l) => sys.error("Impossible!"))

    implicit def cconsCase[H, T <: Coproduct, L <: HList](
        implicit head: PolyEval.Case.Aux[H, L, Option[H]],
        tail: Case[T, L]) // What is the return type here???)
    = at[H :+: T, L]((c, l) =>
        c match {
          case Inl(h) => PolyEval(h, l)
          case Inr(t) => PolyEvalCop(t, l)
      })
  }
}
object-CoproductSample{
导入无形状。{CNil,余积,HList,HNil,Inl,Inr,Poly2,:,:+:}
//从HList中的A=>A累加普通函数
def accum[A,LA,hl:L:(A=>A)::L=f::hl
//一种计算函数中某些单态函数的poly2函数
//满足此函数签名的特定值的HList
对象polyVal扩展了Poly2{
隐式定义hnilCase[A]:Case.Aux[A,HNil,选项[A]]=
在[A,HNil]((A,l)=>无)
隐式def hheadcasessuccess[A,ta]:T,选项[A]]=
在[A,(A=>A)::T]((A:A,l:(A=>A)::T=>Option(l.head(A)))
隐式def hheadcasefil[A,H,th]:T,选项[A]]=
在[A,(H=>H)::T]((A:A,l:(H=>H)::T=>PolyEval(A,l.tail))
}
//一种poly2函数,它使用“polyVal”来计算
//单态函数HList的一个余积
对象polyValCop扩展Poly2{
隐式def cnilCase[A PolyEvalCop(t,l)
})
}
}
控制台会话:

scala> import shapeless._, CoproductSample._
import shapeless._
import CoproductSample._

scala> case class Foo(i: Int); case class Bar(s: String)
defined class Foo
defined class Bar

scala> val f = (foo: Foo) => foo.copy(i = foo.i * 2)
f: Foo => Foo = <function1>

scala> val g = (bar: Bar) => bar.copy(s = bar.s + "_changed!")
g: Bar => Bar = <function1>

scala> val hl = accum(g, accum(f, HNil))
hl: shapeless.::[Bar => Bar,shapeless.::[Foo => Foo,shapeless.HNil.type]] = <function1> :: <function1> :: HNil

scala> type C = Foo :+: Bar :+: CNil
defined type alias C

scala> PolyEvalCop(Coproduct[C](Foo(10)), hl)
res1: Any = Some(Foo(20))

scala> PolyEvalCop(Coproduct[C](Bar("bar")), hl)
res2: Any = Some(Bar(bar_changed!))
scala>import shapeless.\ux,共产品示例_
进口不成形_
导入副产品样本_
scala>case类Foo(i:Int);case类Bar(s:String)
定义类Foo
定义的类栏
scala>valf=(foo:foo)=>foo.copy(i=foo.i*2)
f:Foo=>Foo=
scala>valg=(bar:bar)=>bar.copy(s=bar.s+“_changed!”)
g:Bar=>Bar=
scala>val hl=accum(g,accum(f,HNil))
hl:shapeless.:[Bar=>Bar,shapeless.:[Foo=>Foo,shapeless.HNil.type]]=::HNil
scala>类型C=Foo:+:Bar:+:CNil
定义的类型别名C
scala>PolyEvalCop(副产物[C](Foo(10)),hl)
res1:Any=Some(Foo(20))
scala>PolyEvalCop(副产品[C](条形),hl)
res2:Any=Some(Bar(Bar_已更改!))

结果类型没有被正确跟踪,它被解析为
Any

,从
addF
的签名可以看出,您似乎想映射到
copProduct
,即修改它的值并停留在copProduct上,即
def add[e](e:e):e
,如果是这种情况,这将起作用:

@ {
  trait Add[E]{
    def add(e:E):E
  }
  object Add{
    def apply[E:Add]:Add[E] = implicitly[Add[E]]
    implicit object cnil extends Add[CNil] {
     def add(e:CNil) = throw new RuntimeException("Impossible")
    }
    implicit def coproduct[H, T <: Coproduct](
                 implicit
                 addH: Add[H],
                 addT:Add[T],
                 basis: ops.coproduct.Basis[H :+: T,T]
                 ):Add[H :+: T] = new Add[H :+: T]{
        def add(e: H :+: T) = e match {
           case Inl(h) => Coproduct[H :+: T](addH.add(h)) // to stay in the Coproduct
           case Inr(t) => addT.add(t).embed[H :+: T] // to stay in the coproduct
         }
      }
  }
  }
defined trait Add
defined object Add
@ implicit def addString = new Add[String] {
     def add(e:String) = e + "-ah"
  }
defined function addString
@ implicit def addInt = new Add[Int] {
     def add(e:Int) = e + 1
  }
defined function addInt
@ type C = Int :+: String :+: CNil
defined type C
@ val i = Coproduct[C](1)
i: C = 1
@ Add[C].add(i)
res24: C = 2 // notice that the return type is C
@ val s = Coproduct[C]("a")
s: C = a
@ Add[C].add(s)
res26: C = a-ah // notice that the return type is C
上述内容相当于
map
;但如果您想要
折叠,即
def add[e](e:e):Int
,则只需修改以下两行:

case Inl(h) => addH.add(h)
case Inr(t) => addT.add(t)

我可能会稍后再看,但同时,我建议您使用“-Xlog implicits”编译它谢谢你有趣的回答。然而,我的目的是给用户一个帮助器方法,用它自己的逻辑添加普通函数,而不必为自定义代数编写额外的类型类。我看不出如何使用基于类型类的方法来达到这一目标。事实上,这与我第一次尝试我想尝试类型类的泛型派生。请考虑到我的API的用户将使用自己的类型,我不希望他们不得不处理编写高级代码但简单的纯单态函数的负担。这就是为什么我要寻找一种在HList上累积函数的解决方案,它将启用我知道,不过,我想我记得我读过miles让人沮丧的多边形函数,因为正如你所看到的,它们基本上是特殊类型的类…你用
-Xlog implicits
编译你的例子了吗?是的!我用
-Xlog implicits
编译,这很有帮助。谢谢!我将发布一个upda请稍后使用我目前几乎可以使用的解决方案。
@ Add[Int].add(1)
res38: Int = 2
case Inl(h) => addH.add(h)
case Inr(t) => addT.add(t)