Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
common
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
npm
common
Commits
6603b9c3
Commit
6603b9c3
authored
Jan 23, 2019
by
Vladislav Lagunov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Удален eff
parent
681c0ec6
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
0 additions
and
423 deletions
+0
-423
eff/burrido.ts
+0
-19
eff/index.ts
+0
-404
No files found.
eff/burrido.ts
deleted
100644 → 0
View file @
681c0ec6
import
{
Eff
}
from
'./'
;
import
Monad
from
'burrido'
;
// Do notation
export
const
{
Do
}
=
Monad
({
pure
:
Eff
.
of
,
bind
:
(
m
,
proj
)
=>
m
.
chain
(
proj
),
});
Eff
.
Do
=
Do
;
declare
module
"./index"
{
interface
EffStatics
{
Do
<
Error
,
Success
>
(
iter
:
()
=>
IterableIterator
<
Eff
<
Error
,
Success
>>
):
Eff
<
Error
,
Success
>
;
}
}
eff/index.ts
deleted
100644 → 0
View file @
681c0ec6
import
*
as
either
from
'../either'
;
import
{
Either
}
from
'../either'
;
import
{
absurd
}
from
'../types'
;
// Alias
export
type
Cmd
<
Action
>
=
Eff
<
never
,
Action
>
;
// ADT
export
type
Eff
<
Error
,
Success
>
=
|
Pure
<
Error
,
Success
>
// { value: Either<Error, Success> }
|
Thunk
<
Error
,
Success
>
// { args: unknown[], run(...args): Either<Error, Success> }
|
Subscribe
<
Error
,
Success
>
// { subscribe(onNext: (x: Either<Error, Success>) => void, onComplete: () => void): () => void }
|
Batch
<
Error
,
Success
>
// { steps: Eff<Error, Success>[] }
|
Concat
<
Error
,
Success
>
// { steps: Eff<Error, Success>[] }
|
Apply
<
Error
,
Success
>
// { args: Eff<unknown>[], proj(...args): Either<Error, Success> }
|
Chain
<
Error
,
Success
>
// { first: Eff<unknown>, andThen(x: unknown): Eff<Error, Success> }
|
HasEffect
<
Error
,
Success
>
// { toEffect(): Eff<Error, Success> }
;
export
type
AnyEff
=
Eff
<
any
,
any
>
;
// Instance methods for `Eff`
export
class
EffBase
<
Error
,
Success
>
{
readonly
_Error
:
Error
;
readonly
_Success
:
Success
;
map
<
Success2
>
(
proj
:
(
value
:
Success
)
=>
Success2
):
Eff
<
Error
,
Success2
>
{
return
this
.
mapE
(
ethr
=>
ethr
.
map
(
proj
));
}
mapTo
<
Success2
>
(
value
:
Success2
):
Eff
<
Error
,
Success2
>
{
return
this
.
mapE
(
ethr
=>
ethr
.
mapTo
(
value
));
}
mapError
<
Error2
>
(
proj
:
(
value
:
Error
)
=>
Error2
):
Eff
<
Error2
,
Success
>
{
return
this
.
mapE
(
ethr
=>
ethr
.
mapLeft
(
proj
));
}
mapErrorTo
<
Error2
>
(
value
:
Error2
):
Eff
<
Error2
,
Success
>
{
return
this
.
mapE
(
ethr
=>
ethr
.
mapLeftTo
(
value
));
}
mapE
<
Error2
,
Success2
>
(
proj
:
(
x
:
Either
<
Error
,
Success
>
)
=>
Either
<
Error2
,
Success2
>
):
Eff
<
Error2
,
Success2
>
{
// @ts-ignore
return
new
Apply
([
this
],
proj
);
}
chain
<
Success2
>
(
andThen
:
(
x
:
Success
)
=>
Eff
<
Error
,
Success2
>
):
Chain
<
Error
,
Success2
>
;
chain
<
Error2
,
Success2
>
(
andThen
:
(
x
:
Success
)
=>
Eff
<
Error2
,
Success2
>
):
Chain
<
Error
|
Error2
,
Success2
>
;
chain
<
Error2
,
Success2
>
(
andThen
:
(
x
:
Success
)
=>
Eff
<
Error2
,
Success2
>
):
Chain
<
Error
|
Error2
,
Success2
>
{
// @ts-ignore
return
new
Chain
(
this
.
toEff
(),
ethr
=>
ethr
.
fold
(
failure
,
andThen
));
}
chainTo
<
Success2
>
(
value
:
Eff
<
Error
,
Success2
>
):
Eff
<
Error
,
Success2
>
;
chainTo
<
Error2
,
Success2
>
(
value
:
Eff
<
Error2
,
Success2
>
):
Eff
<
Error
|
Error2
,
Success2
>
;
chainTo
<
Error2
,
Success2
>
(
value
:
Eff
<
Error2
,
Success2
>
):
Eff
<
Error
|
Error2
,
Success2
>
{
return
this
.
chain
(()
=>
value
);
}
chainE
<
Success2
>
(
andThen
:
(
x
:
Either
<
Error
,
Success
>
)
=>
Eff
<
Error
,
Success2
>
):
Eff
<
Error
,
Success2
>
;
chainE
<
Error2
,
Success2
>
(
andThen
:
(
x
:
Either
<
Error
,
Success
>
)
=>
Eff
<
Error2
,
Success2
>
):
Eff
<
Error
|
Error2
,
Success2
>
;
chainE
<
Error2
,
Success2
>
(
andThen
:
(
x
:
Either
<
Error
,
Success
>
)
=>
Eff
<
Error2
,
Success2
>
):
Eff
<
Error
|
Error2
,
Success2
>
{
// @ts-ignore
return
new
Chain
(
this
.
toEff
(),
andThen
);
}
run
(
onNext
:
(
x
:
Either
<
Error
,
Success
>
)
=>
void
,
onComplete
:
()
=>
void
):
()
=>
void
{
return
go
(
this
.
toEff
(),
onNext
,
onComplete
);
}
subscribe
(
onNext
:
(
x
:
Either
<
Error
,
Success
>
)
=>
void
,
onComplete
:
()
=>
void
):
()
=>
void
{
return
go
(
this
.
toEff
(),
onNext
,
onComplete
);
}
toEff
()
{
return
this
as
any
as
Eff
<
Error
,
Success
>
;
}
}
export
function
of
<
A
>
(
value
:
A
):
Pure
<
never
,
A
>
{
return
new
Pure
(
either
.
success
(
value
));
}
export
function
success
<
A
>
(
value
:
A
):
Pure
<
never
,
A
>
{
return
new
Pure
(
either
.
success
(
value
));
}
export
function
failure
<
A
>
(
value
:
A
):
Pure
<
A
,
never
>
{
return
new
Pure
(
either
.
failure
(
value
));
}
export
function
fromCallback
<
L
,
R
>
(
run
:
(
onNext
:
(
x
:
Either
<
L
,
R
>
)
=>
void
,
onComplete
:
()
=>
void
)
=>
()
=>
void
):
Eff
<
L
,
R
>
{
return
new
Subscribe
(
run
);
}
export
function
fromPromise
<
L
,
R
,
Args
extends
unknown
[]
>
(
func
:
(...
args
:
Args
)
=>
Promise
<
Either
<
L
,
R
>>
,
...
args
:
Args
):
Eff
<
L
,
R
>
{
return
new
Subscribe
((
onNext
,
onComplete
)
=>
{
func
(...
args
).
then
(
x
=>
(
onNext
(
x
),
onComplete
()));
return
noopFunc
;
});
}
export
function
fromPromise_
<
L
,
R
>
(
promise
:
Promise
<
R
>
):
Eff
<
unknown
,
R
>
{
return
new
Subscribe
((
onNext
,
onComplete
)
=>
{
promise
.
then
(
x
=>
(
onNext
(
either
.
success
(
x
)),
onComplete
()),
e
=>
(
onNext
(
either
.
failure
(
e
)),
onComplete
()));
return
noopFunc
;
});
}
export
function
fromEither
<
L
,
R
>
(
value
:
Either
<
L
,
R
>
):
Eff
<
L
,
R
>
{
return
new
Pure
(
value
);
}
export
function
thunk
<
L
,
A
,
Args
extends
unknown
[]
>
(
run
:
(...
args
:
Args
)
=>
Either
<
L
,
A
>
,
...
args
:
Args
):
Eff
<
L
,
A
>
{
return
new
Thunk
(
run
as
any
,
args
);
}
export
{
thunk
as
lazy
};
// DEPRECATED
export
function
ap
<
L
,
A
,
B
>
(
a
:
Eff
<
L
,
A
>
,
f
:
(
a
:
A
)
=>
B
):
Eff
<
L
,
B
>
;
export
function
ap
<
L
,
A
,
B
,
C
>
(
a
:
Eff
<
L
,
A
>
,
b
:
Eff
<
L
,
B
>
,
f
:
(
a
:
A
,
b
:
B
)
=>
C
):
Eff
<
L
,
C
>
;
export
function
ap
<
L
,
A
,
B
,
C
,
D
>
(
a
:
Eff
<
L
,
A
>
,
b
:
Eff
<
L
,
B
>
,
c
:
Eff
<
L
,
C
>
,
f
:
(
a
:
A
,
b
:
B
,
c
:
C
)
=>
D
):
Eff
<
L
,
D
>
;
export
function
ap
<
L
,
A
,
B
,
C
,
D
,
E
>
(
a
:
Eff
<
L
,
A
>
,
b
:
Eff
<
L
,
B
>
,
c
:
Eff
<
L
,
C
>
,
d
:
Eff
<
L
,
D
>
,
f
:
(
a
:
A
,
b
:
B
,
c
:
C
,
d
:
D
)
=>
E
):
Eff
<
L
,
E
>
;
export
function
ap
<
L
,
A
,
B
,
C
,
D
,
E
,
F
>
(
a
:
Eff
<
L
,
A
>
,
b
:
Eff
<
L
,
B
>
,
c
:
Eff
<
L
,
C
>
,
d
:
Eff
<
L
,
D
>
,
e
:
Eff
<
L
,
E
>
,
f
:
(
a
:
A
,
b
:
B
,
c
:
C
,
d
:
D
,
e
:
E
)
=>
F
):
Eff
<
L
,
F
>
;
export
function
ap
<
L
,
A
,
B
,
C
,
D
,
E
,
F
,
G
>
(
a
:
Eff
<
L
,
A
>
,
b
:
Eff
<
L
,
B
>
,
c
:
Eff
<
L
,
C
>
,
d
:
Eff
<
L
,
D
>
,
e
:
Eff
<
L
,
E
>
,
f_
:
Eff
<
L
,
F
>
,
f
:
(
a
:
A
,
b
:
B
,
c
:
C
,
d
:
D
,
e
:
E
,
f
:
F
)
=>
G
):
Eff
<
L
,
G
>
;
export
function
ap
():
Eff
<
unknown
,
unknown
>
{
const
args
=
Array
.
prototype
.
slice
.
call
(
arguments
,
0
,
arguments
.
length
-
1
);
const
proj
=
arguments
[
arguments
.
length
-
1
];
return
new
Apply
(
args
,
proj
);
}
export
function
record
<
R
extends
Record
<
string
,
AnyEff
>>
(
rec
:
R
):
Eff
<
{
[
K
in
keyof
R
]:
R
[
K
][
'_Error'
]
}[
keyof
R
],
{
[
K
in
keyof
R
]:
R
[
K
][
'_Success'
]
}
>
{
const
keys
=
Object
.
keys
(
rec
);
return
ap
.
apply
(
undefined
,
[...
keys
.
map
(
k
=>
rec
[
k
]),
(...
values
)
=>
values
.
reduce
((
acc
,
v
,
idx
)
=>
(
acc
[
keys
[
idx
]]
=
v
,
acc
),
{})]);
}
/** Traverse an array */
export
function
traverse
<
Error
,
A
,
B
>
(
array
:
A
[],
f
:
(
a
:
A
,
idx
:
number
)
=>
Eff
<
Error
,
B
>
):
Eff
<
Error
,
B
[]
>
{
if
(
array
.
length
===
0
)
return
success
<
B
[]
>
([]);
return
ap
.
apply
(
undefined
,
[...
array
.
map
(
f
),
(...
args
)
=>
args
]);
}
/**
* Объединение нескольких параллельно выполняемых `Cmd`
*/
export
function
batch
<
Steps
extends
Cmd
<
unknown
>
[]
>
(...
steps
:
Steps
):
Cmd
<
Steps
[
number
][
'_Success'
]
>
;
export
function
batch
<
Steps
extends
Cmd
<
unknown
>
[]
>
(
steps
:
Steps
):
Cmd
<
Steps
[
number
][
'_Success'
]
>
;
export
function
batch
():
Cmd
<
unknown
>
{
const
steps
=
Array
.
isArray
(
arguments
[
0
])
?
arguments
[
0
]
:
arguments
;
return
new
Batch
(
steps
);
}
/**
* Объединение нескольких `Cmd` в очередь
*/
export
function
concat
<
Steps
extends
Cmd
<
unknown
>
[]
>
(...
steps
:
Steps
):
Cmd
<
Steps
[
number
][
'_Success'
]
>
;
export
function
concat
<
Steps
extends
Cmd
<
unknown
>
[]
>
(
steps
:
Steps
):
Cmd
<
Steps
[
number
][
'_Success'
]
>
;
export
function
concat
():
Cmd
<
unknown
>
{
const
steps
=
Array
.
isArray
(
arguments
[
0
])
?
arguments
[
0
]
:
arguments
;
return
new
Batch
(
steps
);
}
/**
* Выполнение сайд-еффектов. Observable не генерирует событий, после
* запуска вызывается переданная функция и Observable завершается.
*/
export
function
forget
<
Args
extends
unknown
[]
>
(
run
:
(...
args
:
Args
)
=>
unknown
,
...
args
:
Args
):
Cmd
<
never
>
{
return
new
Subscribe
((
onNext
,
onComplete
)
=>
{
run
(...
args
);
onComplete
();
return
noopFunc
;
});
}
// Functional helpers
const
noopFunc
=
()
=>
{};
// Perform side effects
export
function
go
<
Error
,
Success
>
(
effect
:
Eff
<
Error
,
Success
>
,
onNext
:
(
x
:
Either
<
Error
,
Success
>
)
=>
void
,
onComplete
:
()
=>
void
):
()
=>
void
{
// @ts-ignore
const
_this
=
this
;
if
(
effect
instanceof
Pure
)
{
onNext
(
effect
.
value
);
onComplete
();
return
noopFunc
;
}
if
(
effect
instanceof
Thunk
)
{
onNext
(
effect
.
_run
.
apply
(
_this
,
effect
.
args
));
onComplete
();
return
noopFunc
;
}
if
(
effect
instanceof
Subscribe
)
{
return
effect
.
subscribe
(
onNext
,
onComplete
);
}
if
(
effect
instanceof
Batch
)
{
if
(
effect
.
steps
.
length
===
0
)
{
onComplete
();
return
noopFunc
;
}
let
subscriptions
:
Array
<
Function
|
null
>
;
const
loop
=
idx
=>
()
=>
{
subscriptions
[
idx
]
=
null
;
for
(
const
unsub
of
subscriptions
)
if
(
unsub
!==
null
)
return
;
onComplete
();
// If control flow reaches here, that means all nested commands are completed
};
subscriptions
=
effect
.
steps
.
map
((
eff
,
idx
)
=>
go
(
eff
,
onNext
,
loop
(
idx
)));
return
()
=>
subscriptions
.
forEach
(
funOrNull
=>
funOrNull
?
funOrNull
()
:
void
0
);
}
if
(
effect
instanceof
Concat
)
{
let
unsubscribe
:
Function
|
null
=
null
;
const
loop
=
idx
=>
()
=>
{
// If condition holds, then all nested effects are completed, therefore we're done
if
(
idx
>=
effect
.
steps
.
length
)
{
onComplete
();
return
;
}
unsubscribe
=
go
(
effect
.
steps
[
idx
],
onNext
,
loop
(
idx
+
1
));
};
loop
(
0
);
return
()
=>
unsubscribe
?
unsubscribe
()
:
void
0
;
}
if
(
effect
instanceof
Chain
)
{
const
cancellers
=
new
Map
<
AnyEff
,
Canceller
>
();
const
handleEffect
=
(
e
:
AnyEff
)
=>
{
const
_onNext
=
result
=>
{
if
(
e
===
effect
.
first
)
handleEffect
(
effect
.
andThen
(
result
));
else
onNext
(
result
);
};
const
_onComplete
=
()
=>
{
if
(
!
cancellers
.
has
(
e
))
completedImmediately
=
true
;
cancellers
.
delete
(
e
);
if
(
cancellers
.
size
===
0
)
onComplete
();
};
let
completedImmediately
=
false
;
const
canceller
=
go
(
e
,
_onNext
,
_onComplete
);
if
(
!
completedImmediately
)
cancellers
.
set
(
e
,
canceller
);
};
handleEffect
(
effect
.
first
);
if
(
cancellers
.
size
===
0
)
return
noopFunc
;
return
()
=>
cancellers
.
forEach
(
canceller
=>
canceller
());
}
if
(
effect
instanceof
Apply
)
{
let
allInitialized
=
false
;
let
subscriptions
:
Array
<
Function
|
undefined
|
null
>
=
new
Array
(
effect
.
args
.
length
);
const
initializedFlags
:
Array
<
true
|
undefined
>
=
new
Array
(
effect
.
args
.
length
);
const
recentValues
:
unknown
[]
=
new
Array
(
effect
.
args
.
length
);
const
next
=
idx
=>
result
=>
{
recentValues
[
idx
]
=
result
;
check_initialized
:
{
if
(
allInitialized
)
break
check_initialized
;
initializedFlags
[
idx
]
=
true
;
for
(
const
flag
of
initializedFlags
)
if
(
flag
!==
true
)
return
;
allInitialized
=
true
;
}
onNext
(
effect
.
proj
.
apply
(
_this
,
recentValues
));
};
const
complete
=
idx
=>
()
=>
{
subscriptions
[
idx
]
=
null
;
for
(
const
unsub
of
subscriptions
)
if
(
unsub
!==
null
)
return
;
onComplete
();
};
effect
.
args
.
forEach
((
eff
,
idx
)
=>
{
const
canceller
=
go
(
eff
,
next
(
idx
),
complete
(
idx
));
if
(
subscriptions
[
idx
]
!==
null
)
subscriptions
[
idx
]
=
canceller
;
});
return
()
=>
subscriptions
.
forEach
(
funOrNull
=>
funOrNull
?
funOrNull
()
:
void
0
);
}
if
(
effect
instanceof
HasEffect
)
{
return
go
(
effect
.
toEffect
(),
onNext
,
onComplete
);
}
return
absurd
(
effect
);
}
export
class
Pure
<
Error
,
Success
>
extends
EffBase
<
Error
,
Success
>
{
constructor
(
readonly
value
:
Either
<
Error
,
Success
>
,
)
{
super
();
}
}
export
class
Thunk
<
Error
,
Success
>
extends
EffBase
<
Error
,
Success
>
{
constructor
(
readonly
_run
:
(...
args
:
unknown
[])
=>
Either
<
Error
,
Success
>
,
readonly
args
:
unknown
[],
)
{
super
();
}
}
export
class
Subscribe
<
Error
,
Success
>
extends
EffBase
<
Error
,
Success
>
{
constructor
(
readonly
subscribe
:
(
onNext
:
(
x
:
Either
<
Error
,
Success
>
)
=>
void
,
onComplete
:
()
=>
void
)
=>
()
=>
void
,
)
{
super
();
}
}
export
class
Batch
<
Error
,
Success
>
extends
EffBase
<
Error
,
Success
>
{
constructor
(
readonly
steps
:
Eff
<
Error
,
Success
>
[],
)
{
super
();
}
}
export
class
Concat
<
Error
,
Success
>
extends
EffBase
<
Error
,
Success
>
{
constructor
(
readonly
steps
:
Eff
<
Error
,
Success
>
[],
)
{
super
();
}
}
export
class
Apply
<
Error
,
Success
>
extends
EffBase
<
Error
,
Success
>
{
constructor
(
readonly
args
:
Eff
<
Error
,
unknown
>
[],
readonly
proj
:
(...
args
)
=>
Either
<
Error
,
Success
>
)
{
super
();
}
}
export
class
Chain
<
Error
,
Success
>
extends
EffBase
<
Error
,
Success
>
{
constructor
(
readonly
first
:
Eff
<
Error
,
unknown
>
,
readonly
andThen
:
(
x
:
Either
<
Error
,
unknown
>
)
=>
Eff
<
Error
,
Success
>
)
{
super
();
}
}
export
abstract
class
HasEffect
<
Error
,
Success
>
extends
EffBase
<
Error
,
Success
>
{
abstract
toEffect
():
Eff
<
Error
,
Success
>
;
}
/**
* Примитивный `Cmd` не генерирует никаких действий, завершается сразу
* после запуска.
*/
export
const
noop
:
Cmd
<
never
>
=
new
Batch
([]);
export
type
Canceller
=
()
=>
void
;
export
interface
EffStatics
{
of
:
typeof
of
,
success
:
typeof
success
,
failure
:
typeof
failure
,
fromCallback
:
typeof
fromCallback
,
fromPromise
:
typeof
fromPromise
,
fromPromise_
:
typeof
fromPromise_
,
fromEither
:
typeof
fromEither
,
thunk
:
typeof
thunk
,
lazy
:
typeof
thunk
,
ap
:
typeof
ap
,
record
:
typeof
record
,
batch
:
typeof
batch
,
concat
:
typeof
concat
,
forget
:
typeof
forget
,
go
:
typeof
go
,
noop
:
typeof
noop
,
}
export
const
Eff
=
{
of
,
success
,
failure
,
fromCallback
,
fromPromise
,
fromPromise_
,
fromEither
,
thunk
,
lazy
:
thunk
,
ap
,
record
,
batch
,
concat
,
forget
,
go
,
noop
,
}
as
EffStatics
;
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment