Comments (7)
Thank you for your interest :)
I think it could be a better expression
I'm not sure if it can be implemented with the signature
If you can implement it, please share itπ
This is something we discussed previously regarding reduce
#130 (comment)
and it would be difficult to change the existing interface because of existing usersπ
from fxts.
@Phryxia Sorry for the late reply.
I also studied what you wrote.
By adding the necessary expressions without breaking the existing usage,
Adding reduceLazy
doesn't seem like a bad idea.
from fxts.
By adding the necessary expressions without breaking the existing usage,
Adding reduceLazy doesn't seem like a bad idea.
Thank you for your response. I'll work this on this weekend.
from fxts.
It's released π
https://fxts.dev/docs/reduceLazy
from fxts.
@ppeeou
Well that's wild. I'll inspect such cass more, and report here.
By the way, can you give an actual example of seed
being iterable please? I haven't understood the situation of seed
being iterable so that curry
can be used. (Not the vague cases in #130. I comprehended them)
from fxts.
It turns out that there is no way to support both seed and high order reduce in a single function signature.
Terminology
Let's define some terminology for this issue.
reducer
: function parameter ofreduce
to merge incomming values.reducer
have at least two parameters.acc
(which is abbreviation of accumulation) is the first parameter ofreducer
, has merged thing from past.value
is the second parameter ofreducer
, fed by iterable things.
reduce
is homogeneous iff type ofacc
= type ofvalue
reduce
is heterogeneous iff it's not homogeneous.reduce
is 2st order returning iff it returns a function.reduce
is 1st order returning iff it's not 2st order.
Possibilities
We'd like to support following 6 cases of reduce
. For simplicity, let T
be type fed by programmer, A
be type of acc
, F
be type of reducer
, R
be type of reduce
.
order | homgeneous, no seed | homogeneous, seed | heterogeneous, seed |
---|---|---|---|
1st | F = (T Γ T) β T R = (F Γ I<T>) β T |
F = (T Γ T) β T R = (F Γ T Γ I<T>) β T |
F = (A Γ T) β A R = (F Γ A Γ I<T>) β A |
2nd | F = (T Γ T) β T R = F β I<T> β T |
F = (T Γ T) β T R = (F Γ T) β I<T> β T |
F = (A Γ T) β A R = (F Γ A) β I<T> β A |
3 parameter cases don't matter because they're disjoint and support all possible ways of having seed. 1 parameter case is just unique so let's ignore them.
The major problem is solving confusing cases which have 2 parameters.
- 1st, homogeneous, no seed
- 2nd, homogeneous, seed
- 2nd, heterogeneous, seed
Our goal is making TypeScript distinguish these three cases.
Ambiguity
Complete logic of type inference is not well known (and I don't know either), but one thing is sure: It's imperfect and kind of greedy (I think backtracking may cause exponential inference time). As my guess, following seems to be true.
- If types in generic are explicitly given, then it judges its parameters.
- If types in generic are not given, but implicitly inferrable, it'll try to find the best matching declaration.
- If it fails, it just fallback to first possibilitiy in branch.
So let's discard the first explicit case. Now we assume that user may give imperfect partial type information via parameters.
Theorem 1
If
T
is not iterable of something, these 3 cases are distinguishable.
Since T
never be iterable, if second parameter is inferred as iterable, then it must be 1st, homo, no seed
. Otherwise they must be one of 2nd, homo, seed
and 2nd, hetero, seed
.
Theorem 2
If
T
is iterable of something, there is a situation where TypeScript can't distinguish them.
When I<T>
is known, but T
is not known
reduce((acc: any, value: unknown) => unknown, Iterable<number>)
Since the only source to infer T
is second parameter Iterable<number>
, TypeScript just tries T := number
. And there is always such matching, which is 1st, homo, no seed
, it always infer as first case. But try this code.
const fn = reduce((acc, value) => [...acc, ...value], [] as Iterable<number>)
Here user might intend T
as Iterable<number>
with seed []
. But value
is already infered as number
, failure occurs.
When T
is known
Sadly it also makes ambiguous case. Following code can be intended as T := number[]
for 2nd, homo, seed
, it's interpreted as 1st, homo, no seed
.
// actual code
reduce((acc, value: number[]) => [...acc, ...value], [])
// user intend
reduce(callback, [] as number[]) // seed
// typescript comprehension
reduce(callback, [] as Iterable<number[]>)
If I even provide I<T>
problem isn't resolved.
// actual code
reduce((acc, value: number[]) => [...acc, ...value], [] as number[])
// user intend
reduce(callback, [] as number[]) // seed
// typescript comprehension
reduce(callback, [] as Iterable<number>)
For your interest, here a typescript playground
Conclusion
There is no way to support both iterable seed and high order function form.
The only dirty alternative is adding new function signature for 2nd order returning case. And actually its implementation is same as original one.
declare function reduceLazy<T>(f: (acc: T, value: T) => T): (it: Iterable<T>) => T
declare function reduceLazy<T>(f: (acc: T, value: T) => T, seed: T): (it: Iterable<T>) => T
declare function reduceLazy<T, A>(f: (acc: A, value: T) => A, seed: A): (it: Iterable<T>) => A
It doesn't break compatibility, and it doesn't introduce any ambiguity. It's really dirty but, the only way to preserve previous usages. If you have more better idea or function name please let me know.
from fxts.
Any further discussion? I think adding reduceLazy
is the best option for current status.
from fxts.
Related Issues (20)
- fromEntries should return partial type HOT 5
- bug: `join` If one numeric parameter is entered, it is returned as number type rather than string.
- feat: enhance entries type HOT 1
- docs: provide recipe for beginner HOT 1
- Type inference is not working when used with Enum HOT 1
- "Type instantiation is excessively deep and possibly infinite" error with large Enum values. HOT 1
- Change `reduce` behavior, When there are two arguments for `reduce`, and the first iterator value is done:true
- docs: support seo HOT 3
- Better documentation and parameter name for `reduce` HOT 2
- Better type declaration for `prop` function HOT 3
- Test of `flat.spec.ts` is broken in `main` branch HOT 2
- Improve readability of package.json
- feat: support fluent Interface
- feat: immutable sort HOT 1
- fxts flatMap causes 'Maximum call stack size exceeded' HOT 1
- docs: Typing Error on fx doc
- How to get string type on pipe? HOT 2
- bug: `flat` type not returned properly in `fx`
- docs: broken links in Guide/Lazy Evaluation document
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from fxts.