Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the Lazy basic implementation much faster... #2

Open
wants to merge 12 commits into
base: master
Choose a base branch
from

Commits on Jan 29, 2017

  1. Make the Lazy basic implementation much faster...

    The current JavaScript Native "memoize" function works by returning a
    nested forcer function when the outer "memoize" function is called to
    initialize the representation of the `Lazy' type with the thunk argument
    so that the evaluated data will later be stored as a local variable
    within the outer "memoize" function's scope when the returned inner
    forcer function is called.  This scheme of bulding a new nested inner
    function "on-the-fly" every time a new `Lazy' is initialized is very
    costly in execution time when run on many current main stream browsers
    such as Chome 55:  http://jsperf.com/iifes-vs-nested-functions/4.
    
    In order to speed this up, the generic `Lazy' type is changed to an Elm
    Tagged Union so that the `force' function can call the Native JS
    "memoize" function on that type without needing to create any new
    functions.
    
    As an added benefit, the Native JS "memoize" function can check for
    recursive evaluation of the thunk and throw an error early rather than
    waiting for a stack overflow on the infinite loop with very little cost
    in execution time.
    
    This change affects the `Lazy a' generic type, the `lazy' type
    constructor function, and the `force' function as well as the Native JS
    "memoize" function; howeverk it makes no changes to the API of the Lazy
    library module.
    
    This speed can be verified by timing the enumeration of the following
    simple natural number lazy list sequence producing function as per the
    following code:
    
    type List a = Node a (Lazy (List a))
    
    nat32s : () -> List Int
    nat32s() =
    let nat32si n =
    Node n << lazy <| \() -> nat32si (n + 1)
    in nat32si 0
    
    nthnat32 : Int -> String
    nthnat32 n =
    let nthnati n nts =
    case nts of
    Node _ tl ->
    if n <= 0 then
    case nts of
    Node hd _ -> toString hd else
    nthnati (n - 1) (force tl)
    in nthnati n (nat32s())
    
    When run using the proposed changes compared to with the original code,
    running `nthnat32 999999' (one million iterations) is faster by about
    six times for Chrome 55 Stable, about four times for Firefox 51 Stable,
    and about two times faster for Microsoft Edge 38.14393.0.0, with all
    three browsers having about the same overall exectution time after the
    change (Chrome was formerly considerably slower than the others).
    
    The version number has only been upped to 2.1.0 although this is a very
    significant change as there are no changes to the API.
    GordonBGood committed Jan 29, 2017
    Configuration menu
    Copy the full SHA
    a5c8cd5 View commit details
    Browse the repository at this point in the history
  2. Merge pull request #1 from GordonBGood/make-faster

    Make the Lazy basic implementation much faster...
    GordonBGood authored Jan 29, 2017
    Configuration menu
    Copy the full SHA
    b69e292 View commit details
    Browse the repository at this point in the history

Commits on Jan 30, 2017

  1. Add lazyFromValue function...

    Once the Lazy type is based on a Tagged Union, it is then advantageous to have a `lazyFromValue` function added to the API so that when an immediately evaluated value that does not need to be deferred is desired, one can create it with this function.  The result is that one level of extra function call to `force` the evaluation is not required when this function is used.
    GordonBGood authored Jan 30, 2017
    Configuration menu
    Copy the full SHA
    bb44d87 View commit details
    Browse the repository at this point in the history

Commits on Jan 31, 2017

  1. Correct example & docs for lazyFromValue

    Corrected example and simplified documentation to reflect a simple use case.
    GordonBGood authored Jan 31, 2017
    Configuration menu
    Copy the full SHA
    ba80812 View commit details
    Browse the repository at this point in the history
  2. Corrected example & added note for `andThen'...

    The previous example was incorrect as to use of arguments for the `cons` function and naming of an argument and non-matching braces for the `append' function; the example code as also been tuned with an inner "wrapper" to reduce the number of arguments.
    
    A note was also added to remind users that this required way of implementing lazy lists inside a `Lazy' wrapper isn't as efficient as non-wrapped due to the many levels of function calls including force/thunk/lazy function calls/compositions required, but that an implementation such as this is required to avoid "The Halting Problem" for creating and use of infinite lazy lists inside a `Lazy' wrapper.
    GordonBGood authored Jan 31, 2017
    Configuration menu
    Copy the full SHA
    85f03ee View commit details
    Browse the repository at this point in the history

Commits on Feb 1, 2017

  1. revert manual version change...

    I didn't realize where versions were set.
    GordonBGood authored Feb 1, 2017
    Configuration menu
    Copy the full SHA
    9a788c2 View commit details
    Browse the repository at this point in the history
  2. support hiding mutation...

    Calling JavaScript Native functions as necessary to support the JavaScript Closure Pattern used to hide mutation from Elm, while at the same time allowing the lazyFromValue call and early recursive evaluation detection (throwing an exception if detected).
    GordonBGood authored Feb 1, 2017
    Configuration menu
    Copy the full SHA
    0b72fe5 View commit details
    Browse the repository at this point in the history
  3. Native support for hiding mutation...

    Using the JavaScript Closure pattern to hide internal mutation, while as the same time detecting recursive evaluation (failing with an exception if detected) and allowing for the use of the lazyFromValue function to avoid unnecessary deferred evaluation for simple values.
    
    Using the "memoize" function from within a Immediately Invoked Function Expression (IIFE) helped with execution speed, in particular on Chrome V8 after many recursions where it seems that some cache/storage overflows and what optimization there is fails.
    GordonBGood authored Feb 1, 2017
    Configuration menu
    Copy the full SHA
    a985025 View commit details
    Browse the repository at this point in the history

Commits on Feb 2, 2017

  1. Final tune for performance...

    Make the inner forcer function as fast as possible when the value has already been evaluated by re-ordering the conditional checks.
    GordonBGood authored Feb 2, 2017
    Configuration menu
    Copy the full SHA
    05444b8 View commit details
    Browse the repository at this point in the history

Commits on Feb 3, 2017

  1. add shared fix' point function for Lazy'...

    This function is a version that uses `Lazy' in its implementation so that it enjoys the recursive evaluation checks introduced with the previous changes.  It forms a recursion on a binding, which can also otherwise be done with a simple anonymous function but without the checks.
    
    This version does not require a recursion limit condition internal to the function argument as the deferred execution ensures that it can not run away indefinitely.
    GordonBGood authored Feb 3, 2017
    Configuration menu
    Copy the full SHA
    7178139 View commit details
    Browse the repository at this point in the history

Commits on Feb 22, 2017

  1. ran elm-format on "lazy.elm" file

    Standardize the formatting.
    GordonBGood authored Feb 22, 2017
    Configuration menu
    Copy the full SHA
    8d9f7da View commit details
    Browse the repository at this point in the history

Commits on Mar 17, 2017

  1. Fixed error in type definition...

    Missed a correction to the type such that the main file will not compile.
    GordonBGood authored Mar 17, 2017
    Configuration menu
    Copy the full SHA
    92566b4 View commit details
    Browse the repository at this point in the history