1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-08-10 22:31:32 +02:00
Files
fp-go/optics/prism/prism.go
Dr. Carsten Leue a87de2f644 fix: use endomorphism in optics
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-18 09:28:36 +01:00

119 lines
3.0 KiB
Go

// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Prism is an optic used to select part of a sum type.
package prism
import (
EM "github.com/IBM/fp-go/endomorphism"
F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option"
)
type (
// Prism is an optic used to select part of a sum type.
Prism[S, A any] interface {
GetOption(s S) O.Option[A]
ReverseGet(a A) S
}
prismImpl[S, A any] struct {
get func(S) O.Option[A]
rev func(A) S
}
)
func (prism prismImpl[S, A]) GetOption(s S) O.Option[A] {
return prism.get(s)
}
func (prism prismImpl[S, A]) ReverseGet(a A) S {
return prism.rev(a)
}
func MakePrism[S, A any](get func(S) O.Option[A], rev func(A) S) Prism[S, A] {
return prismImpl[S, A]{get, rev}
}
// Id returns a prism implementing the identity operation
func Id[S any]() Prism[S, S] {
return MakePrism(O.Some[S], F.Identity[S])
}
func FromPredicate[S any](pred func(S) bool) Prism[S, S] {
return MakePrism(O.FromPredicate(pred), F.Identity[S])
}
// Compose composes a `Prism` with a `Prism`.
func Compose[S, A, B any](ab Prism[A, B]) func(Prism[S, A]) Prism[S, B] {
return func(sa Prism[S, A]) Prism[S, B] {
return MakePrism(F.Flow2(
sa.GetOption,
O.Chain(ab.GetOption),
), F.Flow2(
ab.ReverseGet,
sa.ReverseGet,
))
}
}
func prismModifyOption[S, A any](f func(A) A, sa Prism[S, A], s S) O.Option[S] {
return F.Pipe2(
s,
sa.GetOption,
O.Map(F.Flow2(
f,
sa.ReverseGet,
)),
)
}
func prismModify[S, A any](f func(A) A, sa Prism[S, A], s S) S {
return F.Pipe1(
prismModifyOption(f, sa, s),
O.GetOrElse(F.Constant(s)),
)
}
func prismSet[S, A any](a A) func(Prism[S, A]) EM.Endomorphism[S] {
return EM.Curry3(prismModify[S, A])(F.Constant1[A](a))
}
func Set[S, A any](a A) func(Prism[S, A]) EM.Endomorphism[S] {
return EM.Curry3(prismModify[S, A])(F.Constant1[A](a))
}
func prismSome[A any]() Prism[O.Option[A], A] {
return MakePrism(F.Identity[O.Option[A]], O.Some[A])
}
// Some returns a `Prism` from a `Prism` focused on the `Some` of a `Option` type.
func Some[S, A any](soa Prism[S, O.Option[A]]) Prism[S, A] {
return Compose[S](prismSome[A]())(soa)
}
func imap[S any, AB ~func(A) B, BA ~func(B) A, A, B any](sa Prism[S, A], ab AB, ba BA) Prism[S, B] {
return MakePrism(
F.Flow2(sa.GetOption, O.Map(ab)),
F.Flow2(ba, sa.ReverseGet),
)
}
func IMap[S any, AB ~func(A) B, BA ~func(B) A, A, B any](ab AB, ba BA) func(Prism[S, A]) Prism[S, B] {
return func(sa Prism[S, A]) Prism[S, B] {
return imap(sa, ab, ba)
}
}