Module Relude_SequenceZipper.WithSequence
Creates a Zipper using the given SEQUENCE as the backing implementation.
Heavily inspired by Queensland Function Programming Lab Haskell implementation, although without many of the advanced capabilities, like the ListZipperOp stuff. https://github.com/qfpl/list-zipper/blob/master/src/Data/ListZipper.hs
See also this very enlightening presentation about zippers for more background: http://data.tmorris.net/talks/zippers/0a1062fd0526d7ac1f41ade1e4db1465d311b4fd/zippers.pdf
Parameters
S: Relude_Interface.SEQUENCE
Signature
type t('a)
=
;|
Zipper(S.t('a), 'a, S.t('a))
A Zipper type contains a sequence on the left (in reverse order, so that the head of the left sequence is treated as if it's the item immediately to the left of the focus), a focused item, and a sequence on the right.
The left sequence is reversed so that moving the focus one item to the left is an O(1) operation for list-based implementations. Prepending to an array-based implementation might not be O(1), but list is probably the more common use-case for a zipper since it has ideal performance for moving the focus to the left or right. The array-backed implementation has the left reversed too, for API consistency.
let make: a. S.t('a) => 'a => S.t('a) => t('a);
Constructs a Zipper from a left sequence, a focus, and a right sequence.
NB: the left sequence should be given in reverse - the head of the left sequence is treated as the item immediately to the left of the focus. The right sequence is in "natural" order where the head of the right sequence is treated as the item immediately to the right of the focus.
let makeWithLeft: a. S.t('a) => 'a => t('a);
Constructs a Zipper from a left sequence and a focus.
NB: the left sequence should be given in reverse - the head of the left sequence is treated as the item immediately to the left of the focus.
let makeWithRight: a. 'a => S.t('a) => t('a);
Constructs a Zipper from a focus and a right sequence.
NB: The right sequence is in "natural" order where the head of the right sequence is treated as the item immediately to the right of the focus.
let makeWithRightArray: a. 'a => array('a) => t('a);
Makes a zipper with a focus at the start and with an array at the tail end
let makeWithRightList: a. 'a => list('a) => t('a);
Makes a zipper with a focus at the start and with a list at the tail end
let makeWithFocus: a. 'a => t('a);
Constructs a zipper with empty left and right sequence, and a single focus.
let fromSequence: a. S.t('a) => option(t('a));
Creates a Zipper from a sequence putting the focus on the first item. If the sequence is empty, None is returned.
let fromArray: a. array('a) => option(t('a));
Makes a zipper from a non-empty list. Returns None if empty.
let fromList: a. list('a) => option(t('a));
Makes a zipper from a non-empty list. Returns None if empty.
let fromNonEmptyArray: a. Relude_NonEmpty.Array.t('a) => t('a);
Makes a zipper from a NonEmptyArray, with the focus on the first item
let fromNea: Relude_NonEmpty.Array.t('a) => t('a);
Makes a zipper from a NonEmptyArray, with the focus on the first item
Alias for fromNonEmptyArray
let fromNonEmptyList: a. Relude_NonEmpty.List.t('a) => t('a);
Makes a zipper from a NonEmptyList, with the focus on the first item
let fromNel: Relude_NonEmpty.List.t('a) => t('a);
Makes a zipper from a NonEmptyList, with the focus on the first item
Alias for fromNonEmptyList
include { ... };
module BsFunctorExtensions: { ... };
let apply: a b. t(('a => 'b)) => t('a) => t('b);
Maps a Zipper of functions over a Zipper
Implementation taken from: https://github.com/qfpl/list-zipper/blob/master/src/Data/ListZipper.hs#L151 At the time of this writing, I don't personally understand why it's implemented this way.
include { ... };
module BsApplyExtensions: { ... };
let applyFirst: Apply.t('a) => Apply.t('b) => Apply.t('a);
let applySecond: Apply.t('a) => Apply.t('b) => Apply.t('b);
let map2: ('a => 'b => 'c) => Apply.t('a) => Apply.t('b) => Apply.t('c);
let map3: ('a => 'b => 'c => 'd) => Apply.t('a) => Apply.t('b) => Apply.t('c) => Apply.t('d);
let map4: ('a => 'b => 'c => 'd => 'e) => Apply.t('a) => Apply.t('b) => Apply.t('c) => Apply.t('d) => Apply.t('e);
let map5: ('a => 'b => 'c => 'd => 'e => 'f) => Apply.t('a) => Apply.t('b) => Apply.t('c) => Apply.t('d) => Apply.t('e) => Apply.t('f);
let tuple2: Apply.t('a) => Apply.t('b) => Apply.t(('a, 'b));
let tuple3: Apply.t('a) => Apply.t('b) => Apply.t('c) => Apply.t(('a, 'b, 'c));
let tuple4: Apply.t('a) => Apply.t('b) => Apply.t('c) => Apply.t('d) => Apply.t(('a, 'b, 'c, 'd));
let tuple5: Apply.t('a) => Apply.t('b) => Apply.t('c) => Apply.t('d) => Apply.t('e) => Apply.t(('a, 'b, 'c, 'd, 'e));
let mapTuple2: ('a => 'b => 'c) => (Apply.t('a), Apply.t('b)) => Apply.t('c);
let mapTuple3: ('a => 'b => 'c => 'd) => (Apply.t('a), Apply.t('b), Apply.t('c)) => Apply.t('d);
let mapTuple4: ('a => 'b => 'c => 'd => 'e) => (Apply.t('a), Apply.t('b), Apply.t('c), Apply.t('d)) => Apply.t('e);
let mapTuple5: ('a => 'b => 'c => 'd => 'e => 'f) => (Apply.t('a), Apply.t('b), Apply.t('c), Apply.t('d), Apply.t('e)) => Apply.t('f);
let pure: a. 'a => t('a);
Lifts a pure value into a Zipper, as the focused value.
Alias for
makeWithFocus
Note: QFPL implementation has
repeat a
on the left and right sides. At the time of this writing, I don't understand why it's implemented this way. I'm not sure if we can implement it this way in a strict language.
module Applicative: BsBastet.Interface.APPLICATIVE with type Applicative.t('a) = t('a);
include { ... };
module BsApplicativeExtensions: { ... };
let liftA1: ('a => 'b) => Applicative.t('a) => Applicative.t('b);
let when_: bool => Applicative.t(unit) => Applicative.t(unit);
let unless: bool => Applicative.t(unit) => Applicative.t(unit);
let all: list(Applicative.t('a)) => Applicative.t(list('a));
let foldLeft: ('b => 'a => 'b) => 'b => t('a) => 'b;
Folds a zipper from left-to-right using an accumulator
let foldRight: ('a => 'b => 'b) => 'b => t('a) => 'b;
Folds a zipper from right-to-left using an accumulator
include { ... };
module BsFoldableExtensions: { ... };
let any: ('a => bool) => Foldable.t('a) => bool;
let all: ('a => bool) => Foldable.t('a) => bool;
let containsBy: ('a => 'a => bool) => 'a => Foldable.t('a) => bool;
let contains: (module BsBastet.Interface.EQ with type t = 'a) => 'a => Foldable.t('a) => bool;
let indexOfBy: ('a => 'a => bool) => 'a => Foldable.t('a) => option(int);
let indexOf: (module BsBastet.Interface.EQ with type t = 'a) => 'a => Foldable.t('a) => option(int);
let minBy: ('a => 'a => BsBastet.Interface.ordering) => Foldable.t('a) => option('a);
let min: (module BsBastet.Interface.ORD with type t = 'a) => Foldable.t('a) => option('a);
let maxBy: ('a => 'a => BsBastet.Interface.ordering) => Foldable.t('a) => option('a);
let max: (module BsBastet.Interface.ORD with type t = 'a) => Foldable.t('a) => option('a);
let countBy: ('a => bool) => Foldable.t('a) => int;
let length: Foldable.t('a) => int;
let size: Foldable.t('a) => int;
let count: Foldable.t('a) => int;
let forEach: ('a => unit) => Foldable.t('a) => unit;
let forEachWithIndex: ('a => int => unit) => Foldable.t('a) => unit;
let find: ('a => bool) => Foldable.t('a) => option('a);
let findWithIndex: ('a => int => bool) => Foldable.t('a) => option('a);
let toList: Foldable.t('a) => list('a);
let toArray: Foldable.t('a) => array('a);
module FoldableSemigroupExtensions: (S: BsBastet.Interface.SEMIGROUP) => { ... };
module FoldableMonoidExtensions: (M: BsBastet.Interface.MONOID) => { ... };
let foldMap: (module BsBastet.Interface.MONOID with type t = 'a) => ('b => 'a) => Foldable.t('b) => 'a;
let foldWithMonoid: (module BsBastet.Interface.MONOID with type t = 'a) => Foldable.t('a) => 'a;
let intercalate: (module BsBastet.Interface.MONOID with type t = 'a) => 'a => Foldable.t('a) => 'a;
module FoldableApplicativeExtensions: (A: BsBastet.Interface.APPLICATIVE) => { ... };
module FoldableMonadExtensions: (M: BsBastet.Interface.MONAD) => { ... };
module FoldableEqExtensions: (E: BsBastet.Interface.EQ) => { ... };
module FoldableOrdExtensions: (O: BsBastet.Interface.ORD) => { ... };
module type TRAVERSABLE_F = (A: BsBastet.Interface.APPLICATIVE) => BsBastet.Interface.TRAVERSABLE with type TRAVERSABLE_F.t('a) = t('a) and type TRAVERSABLE_F.applicative_t('a) = A.t('a);
module Traversable: TRAVERSABLE_F;
let toArray: a. t('a) => array('a);
Converts the Zipper into an array
TODO: not needed with Foldable extensions
let toList: a. t('a) => list('a);
Converts the Zipper into a list
TODO: not needed with Foldable extensions
let toNonEmptyArray: a. t('a) => Relude_NonEmpty.Array.t('a);
Converts the Zipper into a NonEmptyArray
let toNea: a. t('a) => Relude_NonEmpty.Array.t('a);
Converts the Zipper into a NonEmptyArray
Alias for toNonEmptyArray
let toNonEmptyList: a. t('a) => Relude_NonEmpty.List.t('a);
Converts the Zipper into a NonEmptyList
let toNel: a. t('a) => Relude_NonEmpty.List.t('a);
Converts the Zipper into a NonEmptyList
Alias for toNonEmptyList
let concatWithKeepLeftFocus: prefix:t('a) => t('a) => t('a);
Concatenates two Zippers, keeping the focus from the left Zipper
let concat: prefix:t('a) => t('a) => t('a);
Concatenates two Zippers, keeping the focus from the left Zipper
Alias for
concatWithKeepLeftFocus
let concatWithKeepRightFocus: prefix:t('a) => t('a) => t('a);
Concatenates two Zippers, keeping the focus from the right Zipper
module Semigroup_Any: BsBastet.Interface.SEMIGROUP_ANY with type Semigroup_Any.t('a) = t('a);
let zipWith: a b c. ('a => 'b => 'c) => t('a) => t('b) => t('c);
Zips two zippers together pair-wise using the given function
let zipWithIndex: a. t('a) => t(('a, int));
Pairs each item in the zipper with it's index as if the zipper was converted to a list or array.
let getFocus: a. t('a) => 'a;
Gets the item at the focus
let getLeft: a. t('a) => S.t('a);
Gets the sequence to the left of the focus (in the unchanged reverse order in which its stored)
let setLeft: a. S.t('a) => t('a) => t('a);
Sets the sequence to the left of the focus. Note: the given sequence should be in reverse so that the head of the sequence is the item that should immediately to the left of the focus.
let getLeftInOrder: a. t('a) => S.t('a);
Gets the sequence to the left of the focus (in its sequential order, i.e. reversed from how its stored in the zipper)
let setLeftFromInOrder: a. S.t('a) => t('a) => t('a);
Sets the sequence to the left of the focus from an in-order sequence. I.e. the given sequence will be reversed by this function when stored in the new zipper.
let getRight: a. t('a) => S.t('a);
Gets the sequence to the right of the focus (order is in order, i.e. not changed)
let setRight: a. S.t('a) => t('a) => t('a);
Sets the sequence to the right of the focus (order is not changed)
let peekLeft: a. t('a) => option('a);
Gets the item to the immediate left of the focus
let peekRight: a. t('a) => option('a);
Gets the item to the immediate right of the focus
let isAtStart: a. t('a) => bool;
Indicates if the focus is at the start of the zipper
let isAtEnd: a. t('a) => bool;
Indicates if the focus is at the end of the zipper
let isAtIndex: a. int => t('a) => bool;
Indicates if the focus is at the given index of the zipper
let isAtItemBy: a. ('a => 'a => bool) => 'a => t('a) => bool;
Indicates if the focus is at the item, based on the given equality function
let isAtItem: (module BsBastet.Interface.EQ with type t = 'a) => 'a => t('a) => bool;
Indicates if the focus is at the item, based on the given EQ module
let moveLeft: a. t('a) => option(t('a));
Moves the focus one item to the left. If there are no items to the left, returns None.
let moveRight: a. t('a) => option(t('a));
Moves the focus one item to the right. If there are no items to the right, returns None.
let moveLeftWithClamp: a. t('a) => t('a);
Moves the focus one item to the left, unless we are at the start.
let moveRightWithClamp: a. t('a) => t('a);
Moves the focus one item to the right, unless we are at the end.
let moveLeftWithWrap: a. t('a) => t('a);
Moves the focus one item to the left, wrapping to the end if we are currently at the start.
let moveRightWithWrap: a. t('a) => t('a);
Moves the focus one item to the right, wrapping to the start if we are currently at the end.
let moveLeftTimes: a. int => t('a) => option(t('a));
Moves the focus a number of times to the left. If the count is out of range, None is returned
let moveRightTimes: a. int => t('a) => option(t('a));
Moves the focus a number of times to the right. If the count is out of range, None is returned
let moveLeftTimesWithClamp: a. int => t('a) => t('a);
Moves the focus a number of times to the left. If the count is out of range, the focus is moved to the start.
let moveRightTimesWithClamp: a. int => t('a) => t('a);
Moves the focus a number of times to the right. If the count is out of range, the focus is moved to the start.
let moveToIndex: a. int => t('a) => option(t('a));
Moves the focus to the given index. If the index is out of range, None is returned.
let moveToIndexWithMod: a. int => t('a) => t('a);
Moves the focus to the given index modulus the length of the zipper.
let moveToIndexWithClamp: a. int => t('a) => t('a);
Moves the focus to the given index, but no farther than the start or end if the index is out of range in either direction.
let findLeftBy: ?checkFocus:bool => ('a => bool) => t('a) => Relude_Option.Monad.t(t('a));
Finds the first item that satisfies the given predicate, and returns a zipper focused on that item.
Note this only searches the focus and the left side of the zipper.
let findRightBy: ?checkFocus:bool => ('a => bool) => t('a) => Relude_Option.Monad.t(t('a));
Finds the first item that satisfies the given predicate, and returns a zipper focused on that item.
Note this only searches the focus and the right side of the zipper.
let findBy: ?checkFocus:bool => ('a => bool) => t('a) => option(t('a));
Finds the first item that satisfies the given predicate, and returns a zipper focused on that itme. The left side is searched first, then the right.
let findItemLeftBy: ?checkFocus:bool => ('a => 'a => bool) => 'a => t('a) => option(t('a));
Finds the given item at the focus or to the left, using the given eq function.
let findItemRightBy: ?checkFocus:bool => ('a => 'a => bool) => 'a => t('a) => option(t('a));
Finds the given item at the focus or to the right, using the given eq function.
let findItemBy: ?checkFocus:bool => ('a => 'a => bool) => 'a => t('a) => option(t('a));
Finds the given item using the given eq function. Searches the left side first, then the right.
let findItemLeft: (module BsBastet.Interface.EQ with type t = 'a) => ?checkFocus:bool => 'a => t('a) => option(t('a));
Finds the given item in the left side, using the given EQ module.
let findItemRight: (module BsBastet.Interface.EQ with type t = 'a) => ?checkFocus:bool => 'a => t('a) => option(t('a));
Finds the given item in the right side, using the given EQ module.
let findItem: (module BsBastet.Interface.EQ with type t = 'a) => ?checkFocus:bool => 'a => t('a) => option(t('a));
Finds the given item using the given EQ module. The left side is searched first, then the right.
let insertWithPushLeft: a. 'a => t('a) => t('a);
Inserts a new item at the focus, and pushes the previous focus to the left side
let insertWithPushRight: a. 'a => t('a) => t('a);
Inserts a new item at the focus, and pushes the previous focus to the right side
let deleteWithPullLeft: a. t('a) => option(t('a));
Deletes the item at the focus, and pulls a value from the left side into focus.
If there is no value on the left, None is returned.
let deleteWithPullRight: a. t('a) => option(t('a));
Deletes the item at the focus, and pulls a value from the right side into focus.
If there is no value on the right, None is returned.
let deleteWithPullLeftOrRight: a. t('a) => option(t('a));
Deletes the item at the focus, and tries to pull an item from the left into focus. If there is no item on the left, it tries to pull an item from the right. If there is no item on the right, None is returned.
let showBy: a. ('a => string) => t('a) => string;
Converts a Zipper to a string using the given function
let show: (module BsBastet.Interface.SHOW with type t = 'a) => t('a) => string;
Converts a Zipper to a string using the given SHOW module
let eqBy: a. ('a => 'a => bool) => t('a) => t('a) => bool;
Compares two Zippers for length and pair-wise equality
let eq: (module BsBastet.Interface.EQ with type t = 'a) => t('a) => t('a) => bool;
Compares two lists for length and pair-wise equality using the given EQ module.
module Infix: { ... };