mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-10 22:31:32 +02:00
118 lines
2.9 KiB
Go
118 lines
2.9 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 (
|
|
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]) func(S) S {
|
|
return F.Curry3(prismModify[S, A])(F.Constant1[A](a))
|
|
}
|
|
|
|
func Set[S, A any](a A) func(Prism[S, A]) func(S) S {
|
|
return F.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, A, B any](sa Prism[S, A], ab func(A) B, ba func(B) A) Prism[S, B] {
|
|
return MakePrism(
|
|
F.Flow2(sa.GetOption, O.Map(ab)),
|
|
F.Flow2(ba, sa.ReverseGet),
|
|
)
|
|
}
|
|
|
|
func IMap[S, A, B any](ab func(A) B, ba func(B) A) func(Prism[S, A]) Prism[S, B] {
|
|
return func(sa Prism[S, A]) Prism[S, B] {
|
|
return imap(sa, ab, ba)
|
|
}
|
|
}
|