Heterogenous sequence for Record
See original GitHub issueI’ve previously implemented Heterogenous sequence for record of promises:
/**
* Removes Promise
*/
export type UnPromise<T> = T extends PromiseLike<infer R> ? R : T;
type AnyRecord = Record<keyof object, unknown>;
/**
* Nicely typed Promise.all for records.
*
* Example:
* ```
// const x: {
// user: { name: string };
// avatar: string;
// age: number;
// }
const x = await parRecord({
user: Promise.resolve({name:"irakli"}),
avatar: Promise.resolve(":)"),
age: 25,
})
```
*/
export const parRecord = <T extends AnyRecord>(
r: T
): Promise<{ [K in keyof T]: UnPromise<T[K]> }> =>
Promise.all(Object.values(r)).then((results) => {
const res = Object.fromEntries(
Object.keys(r).map((key, idx) => [key, results[idx]])
);
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return res as { [K in keyof T]: UnPromise<T[K]> };
});
and I thought I could adopt this approach and make the sequence of Record heterogenous. I wrote the following, it complies, but in practice all fields of record are inferred as unkown
. Just sharing in case someone can spot an issue that could be fixed:
import { HKT, Kind, Kind2, Kind3, URIS, URIS2, URIS3 } from "fp-ts/HKT";
import {
Applicative,
Applicative1,
Applicative2,
Applicative2C,
Applicative3,
Applicative3C,
} from "fp-ts/lib/Applicative";
import * as RR from "fp-ts/ReadonlyRecord";
type UnKind3<F extends URIS3, R, E, T> = T extends Kind3<F, R, E, infer A>
? A
: never;
type UnKind2<F extends URIS2, E, T> = T extends Kind2<F, E, infer A>
? A
: never;
type UnKind<F extends URIS, T> = T extends Kind<F, infer A> ? A : never;
type UnHKT<F, T> = T extends HKT<F, infer A> ? A : never;
export function sequenceR<F extends URIS3>(
F: Applicative3<F>
): <R, E, T extends Record<keyof object, Kind3<F, R, E, any>>>( //
ta: T
) => Kind3<F, R, E, { [K in keyof T]: UnKind3<F, R, E, T[K]> }>;
export function sequenceR<F extends URIS3, E>(
F: Applicative3C<F, E>
): <R, T extends Record<keyof object, Kind3<F, R, E, any>>>( //
ta: T
) => Kind3<F, R, E, { [K in keyof T]: UnKind3<F, R, E, T[K]> }>;
export function sequenceR<F extends URIS2>(
F: Applicative2<F>
): <E, T extends Record<keyof object, Kind2<F, E, any>>>( //
ta: T
) => Kind2<F, E, { [K in keyof T]: UnKind2<F, E, T[K]> }>;
export function sequenceR<F extends URIS2, E>(
F: Applicative2C<F, E>
): <T extends Record<keyof object, Kind2<F, E, any>>>( //
ta: T
) => Kind2<F, E, { [K in keyof T]: UnKind2<F, E, T[K]> }>;
export function sequenceR<F extends URIS>(
F: Applicative1<F>
): <T extends Record<keyof object, Kind<F, any>>>( //
ta: T
) => Kind<F, { [K in keyof T]: UnKind<F, T[K]> }>;
export function sequenceR<F>(
F: Applicative<F>
): <T extends Record<keyof object, HKT<F, any>>>( //
ta: T
) => HKT<F, { [K in keyof T]: UnHKT<F, T[K]> }> {
return (RR.sequence(F) as unknown) as any;
}
Issue Analytics
- State:
- Created a year ago
- Comments:5
Top Results From Across the Web
Learning from heterogeneous temporal data in electronic ...
Each sequence represents the record of one clinical measurement, i.e. one variable, during the defined time period for one patient.
Read more >Learning from heterogeneous temporal data in ... - PubMed
In this study, novel representations of temporal data in electronic health records are explored. These representations retain the sequential information, and ...
Read more >Modeling heterogeneous clinical sequence data in semantic ...
Modeling heterogeneous clinical sequence data in semantic space for adverse drug event detection ... Abstract: The enormous amounts of data that are continuously ......
Read more >Deep Sequence-to-Sequence Entity ... - ACM Digital Library
Deep Sequence-to-Sequence Entity Matching for Heterogeneous Entity ... Entity Resolution (ER) identifies records from different data sources ...
Read more >Deep Sequence-to-Sequence Entity Matching ... - ResearchGate
Request PDF | Deep Sequence-to-Sequence Entity Matching for Heterogeneous Entity Resolution | Entity Resolution (ER) identifies records from different data ...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
You found the answer yourself, but here’s my explanation for future readers:
We usually do something like this:
The suffix
S
here stands forstruct
, which is what you describe as ‘heterogenous’: a type with well known (‘literal’) properties, as opposed to arecord
, which is (usually)Record<string, whatever>
.So if you had something like
Promise.Apply
, you could do this:So, here’s your Promise.Apply:
The problem with
Promise
is that while you can construct a type likePromise<Promise<string>>
, you cannot actually construct a value of that type;Promise.resolve(Promise.resolve('hello'))
isPromise<string>
. This inability to nestPromise
apparently breaks some laws of category theory or something, I don’t understand it myself yet. Which is why JS’sPromise
is generally frowned upon in the FP community and we preferTask
, for this and other reasons.One other reason is that you cannot delay resolution of a
Promise
. Once you create your record{ user: api.getUser('irakli'), age: api.getAge('irakli') }
, all those api calls immediately run. Which means we can not use thisApply
to sequentially work through an array of asynchronous operations (e.g. api calls). WithTask
we can do that.So long answer short, you should probably just use
Apply.sequenceS(Task.ApplyPar)
, which even comes with a choice ofTask.ApplyPar
vs.Task.ApplySeq
, effortlessly allowing you switch between parallel (‘eager’) or sequential (‘lazy’) Promise resolution.The state of a
Promise
is if it isPending
,Resolved
orRejected
. A resolved promise runs only once and stays in this state. You already show that there needs to be some internal state that has changed cause runningsetResolvedValue(42)
twice resolves in two different results. In the first something is logged in the other case not. It is not about that you change thePromise
result, it’s about that a side effect changes thePromise
state.