13

私はPartialFunctionMonoidであると考えました。私の思考プロセスは正しいのですか?例えば 、Scala PartialFunctionはMonoidですか?

import scalaz._ 
import scala.{PartialFunction => -->} 

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

implicit def partialFunctionZero[A,B]:Zero[A-->B] = new Zero[A-->B]{ 
    val zero = new (A-->B){ 
    def isDefinedAt(a:A) = false 
    def apply(a:A) = sys.error("error") 
    } 
} 

しかしScalaz(6.0.4)は、それが含まれていない現在のバージョン。含まれていないものがある理由はありますか?

+0

を、私はあなたが 'Function1'が組成物の下でモノイドであることを知っていると仮定? –

+1

@dcsobral 'Function1 [A、A]'、別名「Endo [A]」です。 – retronym

答えて

28

これについては別の光を照らしましょう。

PartialFunction[A, B]A => Option[B]と同形です。私たちはあなたの主張を証明してきたMonoid[A => Option[B]]を見つけることができるのであれば

(実際に、それは与えられたAのために定義されている場合Bの評価をトリガすることなくチェックすることができるようにするには、A => LazyOption[B]が必要です)。次のようにMonoid[Z]考える

、我々はMonoid[A => Z]を形成することができます。私たちはZとしてOption[B]を使用するのであれば

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)) 
} 

を、私たちはどのようなモノイド(複数可)を持っていますか? Scalazは3つを提供します。プライマリインスタンスにはSemigroup[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) 

をしかし、それには2つのオプションを組み合わせるための唯一の方法ではありません。 2つのオプションの内容を両方ともSomeの場合に追加するのではなく、2つのオプションの最初または最後を選択するだけです。 2つはこれをトリガし、Tagged Typesと呼ばれる特殊なタイプのトリックを作成します。これはHaskellのnewtypeと似ています。それはMonoidだを通じて追加

scala> import Tags._ 
import Tags._ 

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

scala> Monoid[Option[Int] @@ Last].append(Tag(Some(1)), Tag(Some(2))) 
res11: [email protected]@[Option[Int],scalaz.Tags.Last] = Some(2) 

Option[A] @@ First、あなたの例と同じorElseセマンティクスを使用しています。だから、

、すべて一緒にこれを置く:

scala> Monoid[A => Option[B] @@ First] 
res12: scalaz.Monoid[A => [email protected]@[Option[B],scalaz.Tags.First]] = 
     [email protected] 
+0

ありがとう!私はPartialFunctionがA => LazyOption [B] –

+0

に同型であることに気付きませんでした。ありがとう、@retronym!タグ付きの型はscalaz-7でしか使用できません。以前のバージョンでは、FirstOptionの型を使用する必要がありますか? – lester

+2

まあまあです。タグ付きタイプは、いくつかの鋭いエッジを持っていますが、残念なことに、推奨する前に、より良いスカラサポートが必要な場合があります。例: 'List(Tag(1))'は 'ClassCastException'を返します。コンパイラの一部が引数をオブジェクト配列として扱い、後の部分をプリミティブ配列として扱います。 – retronym

2

いいえ、これは(非可換型の)モノイドの両方の要件を満たしています。興味深い考え。どのユースケースをサポートしようとしていますか?

+0

申し訳ありませんが、アイデンティティは明らかに違反しています。 –

+1

@Heiko申し訳ありませんが、あなたの声明は明らかに間違っています。答えが間違っていても、少なくとも私にとってははっきりしていません。 – ziggystar

0

あなたのゼロは確かにアイデンティティ要素の公理に違反しますが、アイデンティティ(部分)関数は問題ないと思います。

あなたのアペンドもモノイドの法律を満たしていないが、その代わりにorElseのあなたはandThen(組成)を呼び出すことができます。しかしこれは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 
    } 
} 
+0

反例を挙げることはできますか? – ziggystar

+0

アイデンティティ法:ea = a = ae –

+0

「e」と「a」は違反ですか? – ziggystar

関連する問題