Skip to content

Releases: reazen/relude

v0.40.0

09 Dec 22:01
Compare
Choose a tag to compare

✨ New

Parallel semantics for IO APPLY

  • Implement parallel execution semantics for the IO APPLY typeclass! 🎆
  • Anything that uses an APPLY-based parallelization (apply, map2-5, tuple2-5, mapTuple2-5, all, traverse/sequence, etc.) should now execute the IO operations in parallel rather than sequential.
    • You shouldn't have to change anything - it should just now be parallel when run
  • This was implemented by adding a new Apply constructor to IO, to go along with the Map and FlatMap constructors
  • Prior to this change the IO apply function was implemented in terms of flatMap, which is why it had the sequential execution semantics. Adding Apply allows for parallel semantics.

IO unsafeRunAsyncPar2 and 3

  • Added unsafeRunAsyncPar2 and 3 functions for IO
  • These are used internally to implement the paralell semantics of IO's Apply, so it's better to use apply-based combinators to compose parallel IO values, rather than manually running them using these.
  • That said, if people find these useful, we can add more, like up to the usual 5, or more!

compose function for IO, Result and Option

  • Added a compose function for the above types, which allow you to compose two functions that are each wrapped inside their own functor contexts.
let rec compose:
  'a 'b 'c 'e.
  (t('b => 'c, 'e), t('a => 'b, 'e)) => t('a => 'c, 'e) = ...

let (<<<) = compose;

let andThen:
  'a 'b 'c 'e.
  (t('a => 'b, 'e), t('b => 'c, 'e)) => t('a => 'c, 'e) = ...

let (>>>) = andThen;
  • This was useful for implementing some of the IO pattern matching with the addition of Apply
  • I also made IO, Result, and Option implement Semigroupoid instances using the above compose functions. I'm not 100% sure if this is a valid thing to do, but it seemed reasonable. Happy to be corrected if this is invalid (and at some point we need to add property-based tests).

🚨 Breaking

  • A small breaking change to IO.withDelay - I realized that withDelay was actually creating a new IO that put the delay before the input IO, so I changed this to split the withDelay function into two different versions:

    • withDelayAfter - creates a new IO which when run, will execute the given IO first, then add the delay
    • withDelay - alias for withDelayAfter
    • withDelayBefore - creates a new IO which when run, will execute the delay, then the given IO

The breaking change is that withDelay used to work more like withDelayBefore, but now is just an alias for withDelayAfter. The end result of each of these is the same, they just put the delay at either the start or the end of the IO operation

🗣️ Request for feedback

This change to IO Apply has not been tested super thoroughly other than some high-level unit tests and some production use cases in our app, so I'd love to hear from anyone as to whether the parallel behavior is working for you, or if you encounter any new problems. If you adopt this version of relude in an existing app, I'd recommend exercising all parts of your app which use IO to make sure there are no regressions.

If you do find regressions, I'd recommend reverting the version of relude for now, and I can try to look into specific cases. If you encounter issues, I'd appreciate minimal reproduction test cases, but any sort of issue description would be appreciated. The most useful information is just a description of what IO combinators you're using, and the order in which they are being used (i.e. "we are doing an async, followed by flatMap, apply, summonError, etc.").

v0.39.0

03 Dec 20:15
Compare
Choose a tag to compare

✨ New

  • @johnhaley81 - add Set.update - an operation for removing and adding a value from a Set - likely useful when dealing with mutable values in a Set #198

v0.38.0

20 Nov 07:06
Compare
Choose a tag to compare

✨ New

  • @johnhaley81 - added ApplicativeExtensions.add - a function for running list of applicative effects list(A.t('a)) to produce an A.t(list('a))
    • See discussion on #195 - this all function is automatically added to any type with an Applicative instance that utilizes include ApplicativeExtensions(Applicative)
    • The all function is a specialization of Traversable sequence with the container type of list and the given APPLICATIVE instance
  • Added alt, orElse, ALT instance, and <|> infix operator for IO
    • See #189
    • The alt function is a useful new operation in IO where you can attempt an effect, and if it fails, attempt a "fallback" effect (and so on for as many effects as you want).
    • e.g. io1 <|> io2 <|> io3 <|> etc
    • Because IO is lazy, none of the effects will be run until the chain is run using IO.unsafeRunAsync
    • When run, io1 will be run, and if (and only if) it fails, io2 will be run, and so on
    • See the tests for example usage

v0.37.0

08 Nov 15:54
Compare
Choose a tag to compare

🚨 Breaking

  • Map.compare is now Map.compareBy and it expects the provided comparison function to return an ordering
  • Map.keys and Map.values return a list instead of an array... see keyArray and valueArray for the old behavior

✨ New

  • StringMap (a specialization of Map where the keys are strings) is included for your convenience
  • Map.singleton constructs a Map from a single key and value
  • Map.fromValueList and Map.fromValueArray construct maps from a list('value) or array('value) as long as you can provide a 'value => 'key mapping. Unlike the groupBy functions, these assume that the key returned by your function will be unique for each value.
  • Option now has specializations like Option.String.eq and Option.IO.traverse. It's not quite as built-out as the List and Array specializations, but it's a start

📝 Docs

  • Map now has doc comments, but turns out they get lost when you construct a specialized Map (e.g. StringMap)

✔️ Code quality

  • Lots more tests for Map
  • More option functions are written here, instead of calling off to other libraries

v0.36.1

05 Nov 03:36
Compare
Choose a tag to compare

✨ New

  • Added RIO to Relude and Relude_Globals modules (forgot to do this in v0.36.0)

v0.36.0

05 Nov 03:32
Compare
Choose a tag to compare

✨ New

  • @RawToast - initial implementation of Relude.RIO - the Reader + IO monad for Relude! 🎆 thanks for the contribution. We can iterate and add more things going forward. I'm excited to try it out!

v0.35.0

01 Nov 03:52
Compare
Choose a tag to compare

✨ New

  • @RawToast - added cond and condError to IO and ResultT for doing conditional maniuplation of those types

v0.34.0

30 Oct 04:58
Compare
Choose a tag to compare

✨ New

  • Added concatNamed(~prefix, suffix) function to Semigroup and SemigroupAny Extensions, which affects any module that has a Semigroup or SemigroupAny module and includes the Relude_Extensions_Semigroup|Any module. #150
    • In other words, Array, List, Nel, and Nea now have a concatNamed function that takes a named argument to disambiguate which argument is which
    • The normal concat function is used in the Semigroup|SemigroupAny function with unlabelled args, so I left that one alone
  • Added guard and power to the MonoidAnyExtensions, to bring it inline with MonoidExtensions
  • Added some more random tests to improve coverage

v0.33.0

29 Oct 05:54
Compare
Choose a tag to compare

✔️ Code "quality"

  • Moved extensions/Relude_Extensions_List.re to list/Relude_List_Specializations.re to better categorize what this module is - it is mostly a set of modules that provide extra functions for various specializations of List, like List.String, List.Int, etc. #176
  • Same change as above for Relude_Extensions_Array #176
  • Finally removed the long-lingering Array.rei and List.rei which we've been somewhat pointlessly re-generating for a long time. Our current stance on .rei files is to not use them because of the maintenance burden they introduce because of our wide-spread use of include for typeclass extensions/etc. #109
    • If someday there is a good solution for managing docs in .rei files in the presence of includes, we can revisit the use of .rei files

v0.32.0

29 Oct 05:05
Compare
Choose a tag to compare

✨ New

  • Added Relude.Timer - which contains basic utility functions for scheduling delayed or repeated invocations of functions, returning a cancel function.
    • These are currently backed by Js.Global.setTimeout/setInterval, but this could be abstracted out in the future if needed
    • This currently includes the functions delay, repeat, and repeatTimes, which can all be canceled once scheduled
  • Added Relude.Debounce.debounce - a utility function for creating debounced unit => unit functions
    • The implementation of this might be subject to change going forward - feedback is appreciated
  • Added Relude.Throttle.throttle - a utility function for creating throttled unit => unit functions
    • The implementation of this might be subject to change going forward - feedback is appreciated
  • Added Relude.Js.Animation with some basic bindings for the requestAnimationFrame-related functions
    • At one point I was using these, but that code got removed, so these functions aren't actually used in relude anywhere. I just included them because they are small and harmless, but they can be removed in the future if needed.
  • Added various utility functions in Relude.Function #178
    • memoize0 - utility function for memoizing a unit => 'a function
    • memoize1 - utility function for memoizing a 'a => 'b function, using a string-map-based cache
    • after - utility function for creating a function that suppresses invocations of a given function before a certain number of calls
    • before - utility function for creating a function that suppresses invocations of a given function after a certain number of calls
    • once - utility function for creating a function that suppresses invocations of a given function after one call
    • wrap - utility function for wrapping a given function with functions that manipulate the input and output of the given function
    • negate - utility function for creating a function that is the negation of a given predicate