-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature: add "unfold" ctor and make Sequence use it as the implementa…
…tion.
- Loading branch information
Dierk Koenig
committed
Sep 7, 2023
1 parent
f18ec64
commit 905b137
Showing
6 changed files
with
89 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/** | ||
* @module kolibri.sequence.constructors.unfold | ||
* The idea was thankfully provided by Daniel Kröni. | ||
*/ | ||
import {createMonadicSequence} from "../../util/sequenceUtil/createMonadicSequence.js"; | ||
|
||
export { unfold } | ||
/** | ||
* @typedef StateAndValueType | ||
* @template _S_, _T_ | ||
* @property { _S_ } state | ||
* @property { _T_ } value | ||
*/ | ||
|
||
/** | ||
* @typedef FromStateToNextStateAndValue | ||
* @callback | ||
* @pure The whole idea of `unfold` is to allow a pure function at this point. Depends on developer discipline. | ||
* @template _S_, _T_ | ||
* @param { _S_ } state | ||
* @return { StateAndValueType<_S_, _T_> | undefined } - `undefined` if the sequence cannot produce any more values | ||
*/ | ||
|
||
/** | ||
* Creates a {@link SequenceType} from a callback function that generates the next state and value from the current state. | ||
* The sequence is supposed to be exhausted when the callback returns `undefined`. | ||
* `unfold` abstracts over the proper state management | ||
* in the closure scope of an {@link Iterable}'s iterator function. | ||
* This allows the {@link FromStateToNextStateAndValue} callback function to be pure. | ||
* @template _T_, _S_ | ||
* @param { FromStateToNextStateAndValue<_S_, _T_> } fromStateToNextStateAndValue - callback function to generate the next state and value | ||
* @param { _S_ } initialState | ||
* @return { SequenceType<_T_> } | ||
*/ | ||
const unfold = (initialState, fromStateToNextStateAndValue) => { | ||
|
||
const iterator = () => { | ||
let runningState = initialState; | ||
|
||
const next = () => { | ||
const result = fromStateToNextStateAndValue(runningState); | ||
if (result === undefined) { | ||
return { done: true, value: undefined }; | ||
} else { | ||
runningState = result.state; | ||
return { done: false, value: result.value }; | ||
} | ||
}; | ||
return { next }; | ||
}; | ||
|
||
return createMonadicSequence(iterator); | ||
}; |
25 changes: 25 additions & 0 deletions
25
docs/src/kolibri/sequence/constructors/unfold/unfoldTest.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { TestSuite } from "../../../util/test.js"; | ||
import { unfold } from "./unfold.js"; | ||
import { Seq } from "../seq/seq.js"; | ||
import { Range } from "../range/range.js"; | ||
import { nil } from "../nil/nil.js"; | ||
|
||
const testSuite = TestSuite("Sequence: constructor unfold"); | ||
|
||
testSuite.add("common usage", assert => { | ||
|
||
const empty = unfold(undefined, _ => undefined); | ||
assert.iterableEq(empty, nil); | ||
|
||
const zeroToFour = unfold(0, n => n < 5 ? {state: n + 1, value: n} : undefined); | ||
assert.iterableEq(zeroToFour, Range(4).take(5)); | ||
|
||
const infiniteFibs = unfold( | ||
{last: 0, current: 1}, | ||
( {last, current}) => ({ state: {last: current, current: last + current}, value: last }) | ||
); | ||
assert.iterableEq(infiniteFibs.take(10), Seq(0, 1, 1, 2, 3, 5, 8, 13, 21, 34)); | ||
|
||
}); | ||
|
||
testSuite.run(); |