Scala部分函数可以是幺半群吗?

Scala部分函数可以是幺半群吗?,scala,functional-programming,scalaz,partialfunction,monoids,Scala,Functional Programming,Scalaz,Partialfunction,Monoids,我想可以。我的思维过程正确吗? 比如说, 导入scalaz_ 导入scala.{PartialFunction=>-->} 隐式def partialfunction半群[A,B]:半群[A-->B]=新半群[A-->B]{ def追加(s1:A-->B,s2:=>A-->B):A-->B=s1.orElse(s2) } 隐式def PartialFunction零[A,B]:零[A-->B]=新零[A-->B]{ val zero=新(A-->B){ def isDefinedAt(a:a)=

我想可以。我的思维过程正确吗? 比如说,

导入scalaz_
导入scala.{PartialFunction=>-->}
隐式def partialfunction半群[A,B]:半群[A-->B]=新半群[A-->B]{
def追加(s1:A-->B,s2:=>A-->B):A-->B=s1.orElse(s2)
}
隐式def PartialFunction零[A,B]:零[A-->B]=新零[A-->B]{
val zero=新(A-->B){
def isDefinedAt(a:a)=false
def apply(a:a)=系统错误(“错误”)
}
}

但是当前版本的Scalaz(6.0.4)没有包括在内。有没有不包括在内的原因

不,这看起来不错,满足(非交换)幺半群的两个要求。好主意。您试图支持什么用例?

您的零肯定违反了identity元素的公理,但我认为identity(partial)函数是可以的

您的append也不满足幺半群定律,但是您可以调用and(composition),而不是orElse。但这只适用于A==B:

implicit def partialFunctionSemigroup[A]: Semigroup[A --> A] = new Semigroup[A --> A] {
  def append(s1: A --> A, s2: => A --> A): A-->A = s1 andThen s2
}

implicit def partialFunctionZero[A]: Zero[A --> A] = new Zero[A --> A] {
  val zero = new (A --> A) {
    def isDefinedAt(a:A) = true
    def apply(a:A) = a
  }
}

让我们用不同的眼光来看待这件事

PartialFunction[A,B]
A=>选项[B]
同构。(实际上,为了能够检查它是否是为给定的
a
定义的,而不触发
B
的计算,您需要
a=>LazyOption[B]

所以如果我们能找到一个
Monoid[a=>Option[B]
我们已经证明了你的断言

给定
Monoid[Z]
,我们可以形成
Monoid[A=>Z]
,如下所示:

implicit def readerMonoid[Z: Monoid] = new Monoid[A => Z] {
   def zero = (a: A) => Monoid[Z].zero
   def append(f1: A => Z, f2: => A => Z) = (a: A) => Monoid[Z].append(f1(a), f2(a))
}
那么,如果我们使用
选项[B]
作为
Z
,我们有什么幺半群呢?Scalaz提供了三个。主实例需要一个
半群[B]

implicit def optionMonoid[B: Semigroup] = new Monoid[Option[B]] {
  def zero = None
  def append(o1: Option[B], o2: => Option[B]) = o1 match {
    case Some(b1) => o2 match {
       case Some(b2) => Some(Semigroup[B].append(b1, b2)))
       case None => Some(b1)
    case None => o2 match {
       case Some(b2) => Some(b2)
       case None => None
    }
  }
}
使用此选项:

scala> Monoid[Option[Int]].append(Some(1), Some(2))
res9: Option[Int] = Some(3)
但这并不是将两种选择结合起来的唯一方法。如果这两个选项都是
Some
,那么我们可以简单地选择其中的第一个或最后一个选项,而不是附加这两个选项的内容。两个触发点,我们使用称为标记类型的技巧创建一个不同的类型。这在精神上类似于Haskell的
newtype

scala> import Tags._
import Tags._

scala> Monoid[Option[Int] @@ First].append(Tag(Some(1)), Tag(Some(2)))
res10: scalaz.package.@@[Option[Int],scalaz.Tags.First] = Some(1)

scala> Monoid[Option[Int] @@ Last].append(Tag(Some(1)), Tag(Some(2)))
res11: scalaz.package.@@[Option[Int],scalaz.Tags.Last] = Some(2)
Option[A]@@First
,通过它的
Monoid
附加,使用与示例相同的
orElse
语义

所以,把这些放在一起:

scala> Monoid[A => Option[B] @@ First]
res12: scalaz.Monoid[A => scalaz.package.@@[Option[B],scalaz.Tags.First]] = 
       scalaz.std.FunctionInstances0$$anon$13@7e71732c

你能给出一个反例吗?它违反了哪个
e
a
?你的版本是一个幺半群。OP的版本也是一个幺半群。真丢脸:我原以为抛出异常会违反identity,但正如isDefined将返回false一样,情况并非如此。
(S1或lse zero)==(zero或lse S1)==S1
,那么它违反了什么呢?如果定义了
S1
,则结果为
S1
。如果
S1
zero
(即,未定义),则结果为
zero
@Heiko对不起,但您的陈述显然是错误的。即使答案是错误的,也很不清楚(至少对我来说)。我想你知道
Function1
是组合下的幺半群吗?@dcsobral
Function1[a,a]
,aka
Endo[a]
,是。非常感谢!我没有意识到PartialFunction与A=>LazyOption是同构的[B]谢谢,@retronym!标记类型仅在scalaz seven中可用,对于以前的版本,必须使用FirstOption特性,对吗?@lester yep,没错。标记类型有一些尖锐的边缘,不幸的是,在推荐它们之前,我们可能需要更好的scalac支持。例如:
List(Tag(1))
给出了一个
ClassCastException
,因为编译器的一部分将参数作为对象数组处理,后面的一部分作为基元数组处理。