robotlolita on v4.x
robotlolita on 2.1.0
robotlolita on deferred-message
robotlolita on union-constructors
robotlolita on typescript
robotlolita on gh-pages
robotlolita on logo
robotlolita on v2.3.2
robotlolita on master
Updates changelog, version to 2… More stylistic fixes (compare)
reduce
ing over the list of Tasks and connecting them with .and
. I'm running into an issue with the max call stack being exceeded, but I think it's just because I have so many images... do you have an advice?
function makeInstance() {
^
RangeError: Maximum call stack size exceeded
at makeInstance (/www/nz-topo/node_modules/folktale/adt/union/union.js:86:26)
at new Deferred (/www/nz-topo/node_modules/folktale/concurrency/future/_deferred.js:83:26)
at Task.run (/www/nz-topo/node_modules/folktale/concurrency/task/_task.js:404:22)
at Task._computation (/www/nz-topo/node_modules/folktale/concurrency/task/_task.js:341:36)
at Task.run (/www/nz-topo/node_modules/folktale/concurrency/task/_task.js:445:28)
at Task._computation (/www/nz-topo/node_modules/folktale/concurrency/task/_task.js:341:36)
at Task.run (/www/nz-topo/node_modules/folktale/concurrency/task/_task.js:445:28)
at Task._computation (/www/nz-topo/node_modules/folktale/concurrency/task/_task.js:341:36)
at Task.run (/www/nz-topo/node_modules/folktale/concurrency/task/_task.js:445:28)
at Task._computation (/www/nz-topo/node_modules/folktale/concurrency/task/_task.js:341:36)
// given an array of something and a transform function that takes an item from
// the array and turns it into a task, run all the tasks in sequence.
// inSequence :: (a -> Task) -> Array<a> -> Task
export const inSequence = R.curry((transform, items) => {
let log = [];
return items.reduce((pipe, item, i) => {
// build up a chain of tasks
return (
pipe
// transform this item to a task
.chain(() => transform(item))
// after it's done, push the result to and return the log
.map(result => {
log.push(result);
return log;
})
);
}, Task.of("start"));
});
.and
:
// given an array of something and a transform function that takes an item from
// the array and turns it into a task, run all the tasks concurrently.
// concurrently :: (a -> Task) -> Array<a> -> Task
export const concurrently = R.curry((transform, items) => {
return items.reduce((pipe, item, i) => {
return (
pipe
// transform this item to a task
.and(transform(item))
);
}, Task.of("start"));
});
// given an array of something and a transform funcion that takes an item from
// the array and turns it into a task, run all the tasks in chunks.
// Sometimes, using inSequence or concurrently can go over the max call stack.
// Processing those in chunks solves that error.
// inChunks :: (a -> Task) -> Array<a> -> Task
export const inChunks = R.curry((transform, items) => {
const chunks = R.splitEvery(1000, items);
return inSequence(chunk => {
return concurrently(transform, chunk);
}, chunks);
});
// files is an array of length ~5k
.chain(files => {
return inChunks(file => {
return copyOrMergeTile(file).map(() => file);
}, files);
})
@lax4mike ah, yeah, sadly Task isn't stack safe, so long (synchronous) sequences will blow up the stack. Currently the only way to avoid this is by inserting some asynchronous process in the middle of the long sequence of synchronous ones to clean up the stack.
Generalised effects (https://github.com/robotlolita/effects) will be stack safe, but they might only be added to folktale by the end of this year. I'd like TypeScript to have a way of typing them (even if an unsound one, since soundness would require linear types).
Hello! My name is Matheus, I'm a brazilian developer and a functional JS enthusiast. I'm new here, so, excuse me if I do something wrong.
I use folktalke implementations at work, and I want to thank you very much for that!
Recently I've seen a deprecation warning regarding nullableToResult
telling me that I should pass a second argument, being a default value to it.
getOrElse
on Result.Error
, being a "safe" way of accessing the value inside of it
getOrElse
overrides the default value passed to nullableToResult
(...stuff)
are hard to handle in curried / partial application situations, so purists prefer that you clearly state all arguments vs. providing defaults. Also, we don't have a good "nothing" like other languages like Python. In JavaScript we have undefined
and null
and sometimes ''
. I would stick to getOrElse
, otherwise, you can use matchWith
to use a function to make it based on if it's an Ok
or an Error
.
Result.Error
if the value passed to nullableToResult
is null, or undefined, like here in the docs: https://folktale.origamitower.com/api/v2.3.0/en/folktale.result.fromnullable.html (where it is called feedbackValue
)
feedbackValue
(using docs naming) to nullableToResult
and after that call getOrElse
this feedbackValue
will be overridden by getOrElse
's argument, why then, we are forced to pass a feedbackValue
in nullableToResult
?
Result
with redux-saga, but doing .matchWith
invokes the functions inside instead of returning a function (that happens to be a generator) is there a way to use .chain
, .matchWith
with generators - "redux-saga" ?
var isDataValid = function( target ) {
return Validation.Success( function( a ) {
return function( b ) {
return target;
}
} )
.ap( isEventAndYearSegmentSelected( target ) )
.ap( isIncomeAccountRelevant( target ) )
.ap( isExpenseAccountRelevant( target ) )
};
@JesterXL more than 3 times at this point, but I'm hoping to publish a series of articles explaining what Purr is, how you program in it, and the development plan 'til the end of this month. I haven't had much time lately to work on things because I'm moving and dealing with immigration stuff and the like has been taking all my time.
The current model is much simpler than the old ones, and it has both gradual types and contracts. As for platforms, the idea is having a stand-alone programming platform with different runtimes you can deploy to without having to rewrite things. Currently Node, Electron, and web runtimes are planned. I want to experiment with a .NET runtime in the future if they release CoreRT, since that lets you ship super small cross-platform native applications. This means that you should be able to write a GUI application and deploy it in the browser, Electron, or as a native app without changing anything in your code.
@jk121960 I think the idea of avoiding if/else in general is misguided. It's the simplest thing that works, and it's the best construct for a lot of problems. You'll see it often in mathematics too (though generally expressed f(a) = b, if c; otherwise d
).
There are particular constructs and ideas that, for limited domains, work better than generic branching. For example, the Validation applicative works better for validation than using generic branching—but it's only for validation, you can't really apply that to any other domain. Or the fail-fast approach some monads provide under .chain()
, which gives you a sorta railway-oriented programming style.
You can make if/else a function if you want, so you could write: wrap(thing).andThen(f).andThen(choose(isAcceptable, doA, doB)).andThen(moreThingsGoHere)
, though I particularly think andThen(x => isAcceptable(x) ? doA() : doB())
is clearer and just as concise.
Hello good people, I'm trying the tstypes version of folktale, and was wandering if/how can I import the Task type definition so that I can use it as a return type for some functions of mine.
Things like this:
import {concurrency} from 'folktale';
and then trying to use concurrency.task as a typescript type seem to fail... I feel like I'm missing something obvious