Created
February 14, 2018 13:42
-
-
Save mattiamanzati/788a2989acbff9aab5dde42f7c043919 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. | |
*/ | |
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]: ReadonlyArray<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> | |
/** | |
* | |
* @param varName Nome dell'indice dello Scope contenente un booleano | |
* @param truthy Istruzione da eseguire sullo scope se vero | |
* @param falsy Istruzione da eseguire sullo scope se falso | |
*/ | |
if<K extends keyof T, L, R>(varName: K, truthy: (scope: IScope<T>) => IScope<T & R>, falsy?: (scope: IScope<T>) => IScope<T & L>): IScope<T & ( | |
(L & ({[TK in K]: false})) | | |
(R & ({[TK in K]: true})) | |
)> | |
} | |
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]: ReadonlyArray<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) | |
} | |
if<K extends keyof T, L, R>(varName: K, truthy: (scope: IScope<T>) => IScope<T & R>, falsy?: (scope: IScope<T>) => IScope<T & L>): IScope<T & ( | |
(L & ({[TK in K]: false})) | | |
(R & ({[TK in K]: true})) | |
)> { | |
const realFalsy = falsy ? falsy : (scope: IScope<T>) => scope | |
return new Scope(this._task.chain(scope => scope[varName] ? truthy(this).return<any>(s => s) : realFalsy(this).return<any>(s => s))) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment