Created
June 19, 2018 08:26
-
-
Save mattiamanzati/763b0d1066f24aa2c6bb9beef9734737 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
import { Task, task, sequence, array } from "./fp-ts" | |
import { identity } from "fp-ts/lib/function"; | |
/** | |
* Gli `Scope` sono strutture di supporto per l'esecuzione sequenziale di `Task` asincroni. | |
* | |
* Lo scope si inizializza, si compone di una serie di `let`, `for` e `do` e termina la propria vita a seguito di un `return`. | |
* Tutte le istruzioni dello `Scope` sono garantite di essere eseguite sequenzialmente. | |
* @param T Il tipo dei valori dello Scope indicizzato per nome | |
*/ | |
export interface IScope<T> { | |
/** | |
* Aggiunge o reimposta nello scope attuale il valore dell'indice `varName`. | |
* Il valore deve essere un Task, che quindi viene calcolato in maniera asincrona. | |
* ``` | |
* new Scope() | |
* .let("x", () => task.of(1)) | |
* .let("y", () => task.of(2)) | |
* .return(scope => scope.x + scope.y) // => Task<number> | |
* ``` | |
*/ | |
let<K extends string, J>(varName: K, fn: (scope: T) => Task<J>): IScope<T & {readonly [JK in K]: J}> | |
/** | |
* Data una una funzione che ritorna una array di task, li esegue uno ad uno sequenzialmente, | |
* e setta il risultato di ogni task in una array dello scope sotto l'indice `varName` indicato. | |
* ``` | |
* new Scope() | |
* .for("x", scope => [task.of(1), task.of(2), task.of(3)]) | |
* .return(scope => scope.x) // => Task<number[]> | |
* ``` | |
* @param varName L'indice in cui inserire l'array di risultato | |
* @param fn La funzione che ritorna una array di `Task` da eseguire sequenzialmente. | |
*/ | |
for<K extends string, J>(varName: K, fn: (scope: T) => ReadonlyArray<Task<J>>): IScope<T & {readonly [JK in K]: J[]}> | |
/** | |
* Esegue sequenzialmente una computazione asincrona senza variare lo scope attuale. | |
* ``` | |
* new Scope() | |
* .for("x", () => task.of(1)) | |
* .do(scope => delay(scope.x * 1000)) | |
* .return(scope => scope.x) // => Task<number> | |
* ``` | |
*/ | |
do(fn: (scope: T) => Task<void>): IScope<T> | |
/** | |
* Converte lo `Scope` in un `Task` che si risolve con il valore di ritorno della funzione passata. | |
* ``` | |
* new Scope() | |
* .for("x", () => task.of(1)) | |
* .return(scope => scope.x) // => Task<number> | |
* ``` | |
*/ | |
return<J>(fn: (scope: T) => J): Task<J> | |
} | |
/** | |
* The sequence implementation for Task | |
* @hidden | |
*/ | |
const seq = sequence(task, array) | |
export class Scope<T extends Object = {}> implements IScope<T> { | |
/** | |
* Inizializza un nuovo scope. | |
* @param _task Il task che inizializza il valore dello scope corrente, se omesso, uno vuoto verrà fornito. | |
*/ | |
constructor(protected readonly _task: Task<T> = task.of({}) as any) { | |
} | |
for<K extends string, J>(varName: K, fn: (scope: T) => Task<J>[]): IScope<T & {readonly [JK in K]: J[]}> { | |
return new Scope(this._task.chain(scope => seq(fn(scope)).map(value => Object.assign({}, scope, { [varName]: value })))) as any | |
} | |
let<K extends string, J>(varName: K, fn: (scope: T) => Task<J>): IScope<T & {readonly [JK in K]: J}> { | |
return new Scope(this._task.chain(scope => fn(scope).map(value => Object.assign({}, scope, { [varName]: value })))) as any | |
} | |
do(fn: (scope: T) => Task<void>): IScope<T> { | |
return new Scope(this._task.chain(scope => fn(scope).map(() => scope))) | |
} | |
return<J>(fn: (scope: T) => J): Task<J> { | |
return this._task.map(fn) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment