Giter Site home page Giter Site logo

elm-community / list-extra Goto Github PK

View Code? Open in Web Editor NEW
135.0 6.0 59.0 468 KB

Convenience functions for working with List.

Home Page: http://package.elm-lang.org/packages/elm-community/list-extra/latest

License: MIT License

Elm 100.00%
elm list convenience-functions

list-extra's Introduction

Convenience functions for working with List

Feedback and contributions are very welcome!

Tests

This package uses elm-test and elm-verify-examples.

Contributing

Pull requests are welcome. You can expect some kind of response within 14 days.

If you are proposing a new function be added, please adhere to the following..

  1. Include documentation and make sure your documentation has a code snippet demonstrating what the function does. We use elm-verify-examples in our travis set up which verifies our examples that our example code is correct, so please take advantage of that.
  2. Provide a detailed use case where your new function would be useful. Also, compare your new function to the best possible implementation that doesn't use your function.
  3. Add tests to Tests/Tests.elm

If you are improving existing functions please demonstrate the performance gains in something like Ellie and by using a benchmark library like this one. I usually copy and paste the last ellie bench mark I made, like this one, so I don't have to set up the whole benchmark from scratch every time.

list-extra's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

list-extra's Issues

Add cross

It would be helpful to have this function:

cross : List a -> List b -> List (a,b)

cross [1,2,3] ["a", "b"] = [(1, "a"), (1, "b"), (2, "a"), (2, "b"), (2, "a"), (2, "b")]

The use case I have in mind is getting a list of grid intersections, e.g. cross [0..m] [0..m].

Proposal: new function zipWith()

Hello all,

I'd like to suggest an addtional function zipWith(). It should work exactly like its Haskell counterpart:

Prelude> :t zipWith
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
Prelude> zipWith (\a b -> a * b) [1, 2, 3] [10, 100, 1000]
[10,200,3000]

Implementation should be pretty straightforward - I can provide one if required (but I wanted to ask here first before submitting a pull request).

Kind regards,
Frank

Proposal for push

Hi.

I'm often using something like

pushIn : List a -> a -> List a
pushIn list elem =
  elem :: list

to use it into pipelines

doSomethingWithElems : a -> List a -> List a
doSomethingWithElems myElem allMyElems =
  myElem
    |> doSomethingWithTheElem
    |> pushIn allMyElems

What do you think about it?
It's the exact reverse of (::), but since flip is gone, I think it is worthwhile.

updateAt/setAt/swapAt could return a List (not a Maybe List)

Several functions like removeAt : Int -> List a -> List a or updateIfIndex : (Int -> Bool) -> (a -> a) -> List a -> List a return a List a and that's fine (from my point of view)!

On the other hand, updateAt : Int -> (a -> a) -> List a -> Maybe (List a) returns a Maybe (List a) which is annoying.

May we change this to updateAt : Int -> (a -> a) -> List a -> List a?

The same remark applies to setAt and swapAt.

These functions could return the original list when the index is invalid.

What do you think about it? Shall I send a pull-request in that direction?


Use case:

numbers = [14, 42, 99]

numbers |> updateIfIndex ((==) 0) (\n -> n + 1)
-- should be the same than
numbers |> updateAt 0 (\n -> n + 1)

-- but with current we have to do:
numbers |> updateAt 0 (\n -> n + 1) |> Maybe.withDefault numbers

Remove iterate

There are a number of problems with the iterate function that lead me to believe that it should be removed. At the very least, we should change its signature and rename it.

Iterated functions are almost entirely unrelated to lists. This function belongs in (the hypothetical) Function.Extra not List.Extra (a similar objection was raised to #39 which attempted to add a function for repeated composition).

The name is confusing. The first thing that I (and I presume most other people as well) think of when presented with the words iterate and list is accessing the values of a list in order. Yet iterate has nothing to do with this, instead deriving its name from the mathematical notion of an iterated function (also known as repeated function application).

The current API is awkward and heavily lends from Haskell. In Haskell, presumably where the idea for this function came from, the (Elm translated) signature is (a -> a) -> a -> List a. This works great for Haskell because it supports infinite lists. Elm, on the other hand, does not so the current implementation uses a Maybe to indicate when the iteration should stop. Not only is this awkward but it is also inconsistent with the rest of the library. (If we choose to keep it, the function should instead accept an argument for the desired number of applications and a While variant should be created that accepts a predicate for when to stop.)

Limited use. The example in the current documentation is pretty weak (in particular it is better to use List.range 2010 2030 for that kind of thinig). I was struggling to think of a better example to replace it. All of the things I thought of could be done much more cleanly using other functions.

Suggestion: Deprecate filterNot

I think we want to avoid bloat and rely on simple primitives where we can no?

filterNot can be as simple as using function composition with things implemented in core

List.filter (not << myFunction) myList

The potential danger in keeping something like this around is that users will then expect Not functions for every other data structure. I think it's good that users discover the power of function composition and application and to point them toward core library whenever possible.

Update: I'm open to hearing reasons for keeping it though.

Adding `filterMap` method

I recently found it useful to have a method that filters and maps a list at the same time, with the following type signature:

filterMap : (a -> ( b, Bool )) -> List a -> List b

The mapped value b is included in the resulting list if the boolean value returned in the tuple is true.

Does it make sense to include this in the library? If so, I have an implementation ready and happy to issue a PR.

maximumBy and minimumBy documentation could use a little work

@rlefevre opened up #109 recently, and I had to look into what maximumBy and minimumBy do. I felt like the documentation was a little confusing. Like the term 'first maximum' was unintuitive to me. I guess theres no reason you couldnt have multiple maximums (if the two maximum are equal and above all the others) but its not a part of the normal connotation.

Then also, there are no code examples for these functions. There should be.

Is it just me that finds the documentation on these lacking? I dont really want to go off and fix these things up if its just me.

Proposal for `unconsLast` function

It would be defined something like this:

{-| Decompose a list into its last element and the remaining list. If the list is empty, return `Nothing`. Otherwise, return `Just (x, xs)`, where `x` is the last element and `xs` is rest of the list.

    unconsLast [1,2,3] == Just (3, [1,2])
    unconsLast [] = Nothing
-}
unconsLast : List a -> Maybe ( a, List a )
unconsLast =
    List.reverse
        >> uncons
        >> Maybe.andThen (\( lastElem, reversedList ) -> Just ( lastElem, (List.reverse reversedList) ))

I'd be more than happy to create a merge request using the module formatting for documentation and the like. Let me know.

Non-Empty Discussion

We recently merged a change to groupWhile to make it deal with non-empty lists (a, List a). Until now, we have kind of steered clear of non-empty lists.

So now we have a little bit of non-empty lists in List.Extra. Is that a good move? A bad move? Where do we draw the line? Do we need to draw any lines? Bottom line question is, should we have non-empty list support in List Extra?

My opinion is that theres no problem with a some non-empty list functions. We dont have to support every possible operation, but a few helpers that can make it easy to transform non-empty lists to lists and vice versa would be nice.

setAt wrong params

The thid parameter of List.Extra.setAt is supposed by List a but it's actually List (Maybe a)

Not sure if the documentation needs to be updated or the function needs to be fixed.
imho I would prefer it if we could fix the function!

groupWhile should return a List of Nonempty, not a List of List

groupWhile : (a -> a -> Bool) -> List a -> List (List a)

Should be

groupWhile : (a -> a -> Bool) -> List a -> List (Nonempty a)

The issue is that Nonempty is a different package obviously. But as it stands it's kind of wrong, no? Maybe it belongs on the other package though.

Proposal for `prepend`

Here's an example (super easy way) of doing it:

prepend : List a -> List a -> List a
prepend prependee prepended =
    List.concat [ prepended, prependee ]

If can create a merge request with the appropriate docs and tests if approved.

splitAt traverses n elements twice

The current implementation of splitAt is a simple (take n ls, drop n ls). This traverses n elements twice, first for the take, then for the drop. This could result in bad performance when n is a large number.

New function for finding, which returns a mapped value

I have encountered many scenarios where a function like the following would have been useful:

mapFind : (a -> Maybe b) -> List a -> Maybe b

It's similar to find but it returns a mapped value. Suppose you want to use an expensive function, let's say factorial, on each element to find the first element with a factorial larger than 1000. But you want the resulting factorial rather than the element in the list. Using the existing find function, you'd have to call the factorial function twice, once for finding the element, and once for mapping the resulting Maybe value. With something like the mapFind function above, we could avoid the extra computation:

mapFind
  (\x ->
    let
      y =
        factorial x
    in
      if y > 1000 then Just y else Nothing
  )
  xs

This is a contrived example but I have encountered similar situations a couple of times now, so I thought it would make for a good addition to List.Extra.

I could make the pull request, but I wanted to get some feedback first. I'm also not sure about the name mapFind. This name is similar to how List.filterMap was named, which maps elements first and then filters them. Perhaps it should be called mappedFind instead, but then it wouldn't be consistent with List.filterMap. So I don't know, what should we call it?

Proposal for `splitsAt` function

It would be defined something like this:

{-| Take a number and a list, return a tuple of lists, where first part is prefix of the list of length equal the number, and second part is the remainder of the list. `splitAt n xs` is equivalent to `(take n xs, drop n xs)`.

    splitsAt [2,3] [1,2,3,4,5] == [[1,2],[3],[4,5]]
    splitsAt [2,4] [1,2,3,4,5,6] == [[1,2],[3,4],[5,6]]
    splitsAt [1,2,4] [1,2,3,4,5,6] == [[1],[2],[3,4],[5,6]]
    splitsAt [1] [1,2,3] == [[1],[2,3]]
    splitsAt [3] [1,2,3] == [[1,2,3],[]]
    splitsAt [0] [1,2,3] == [[],[1,2,3]]
    splitsAt [] [1,2,3] == [[1,2,3]]
-}
splitsAt : List Int -> List a -> List (List a)
splitsAt indices list =
    let
        sa : List Int -> List a -> List (List a) -> List (List a)
        sa indices list splits =
            case uncons indices of
                Just ( index, restIndices ) ->
                    let
                        ( split, rest ) =
                            splitAt index list

                        splitLength =
                            List.length split

                        adjustedRestIndices =
                            restIndices
                                |> List.map (flip (-) splitLength)
                    in
                        sa adjustedRestIndices rest (splits ++ [ split ])

                Nothing ->
                    splits ++ [ list ]
    in
        sa indices list []

I'd be more than happy to create a merge request using the module formatting for documentation and the like. Let me know.

Improve and normalize variable names

There are a lot of functions that have parameters named things like "idx" and "l". I think "index" and "list" are better names. It's not like white space is scarce in this project. At the very least, there should be one strategy to variable naming in this repo.

What do you think? Is there value in making this change to the repo? What should the variable names be?

Proposal for `removeFirst` function

Hi folks, I was just missing a function to remove the first element that satisfies a condition. The same goes for replacing. Their types would be:

removeFirst: (a -> Bool) -> List a -> List a
replaceFirst: (a -> Bool) -> a -> List a -> List a

It could be useful to remove by id (or any other field) from a list of records.
What do you think? I would be happy to attempt a PR if you find it suitable.

UniqueBy is implemented using recursion

I have experienced a problem with hitting the maximum call stack size when using uniqueBy on a long list (22,000 entries.) I am not very wise in the ways of these things but it occurs to me that it might be due to the recursive implementation.

I have put together a foldl based implementation that seems to run without issue though i haven't verified that is works properly yet. If it does, would you be interested in a pull request?

uniqueBy : (a -> comparable) -> List a -> List a
uniqueBy f list =
    let
        foldf entry ( set, current ) =
            let
                key =
                    f entry
            in
            if Set.member key set then
                ( set, current )
            else
                ( Set.insert key set, entry :: current )
    in
    List.foldl foldf ( Set.empty, [] ) list
        |> Tuple.second

Improve groupsOfWithStep & greedyGroupsOfWithStep Documentation

The docs for groupsOfWithStep say:

Split list into groups of size given by the first argument. After each group, drop a number of elements given by the second argument before starting the next group.

With this example & test:

groupsOfWithStep 2 1 (range 1 4) == [[1,2],[2,3],[3,4]]

But shouldn't it be something like this(groupsOfWithStep 2 1 (range 1 6)):

[1, 2, 3, 4, 5, 6]
=> [ [1, 2] ]
=> [ [1, 2], [4, 5] ]

It should take 2, then drop 1, then take 2, right? Unless I'm misunderstanding the documentation.

Edit: Same with greedyGroupsOfWithStep?

greedyGroupsOfWithStep 3 2 (range 1 6) == [[1,2,3],[3,4,5],[5,6]]

Should be [ [1, 2, 3], [6] ]?

`chunksOf` function

Would you be open to add a chunksOf function which is defined like this.

{-|
   Given a list make chunks of length n from it
   NOTE: last one can be less than n
 -}
chunksOf : Int -> List a -> List (List a)
chunksOf n xs =
  case xs of
    [] ->
      []

    _ ->
      let
        (ys, zs) = splitAt n xs
      in
        ys :: chunksOf n zs

I searched for a similar function but was unable to find one

Next release

I think its about time for another release? Its been 7 months or something.

I've been worried that with Elm 0.19s new elm.json versioning for applications, that even a minor update would cause dependency problems for people. But I think thats probably been unfounded, and its safe to do a minor update.

Release planning

I bet Elm 0.19 is just around the corner. Since we have a lot of major updates lets wait until 0.19 to publish the next version of list-extra. Does that sound good? After Elm 0.19 comes out we can do a kind of last call on major updates, and do some of the house cleaning tasks like cohering variable names.

Does that sound good?

Proposal for `contains` function

Often I'll find myself doing someList |> List.filter (flip List.member myList).
I assume that other people have this same construct to filter a list.

Would it be nice to have a function in this package that makes this code cleaner. Such as:

contains : List a -> a -> Bool
contains =
    flip List.member

Then the resulting code would be nicer and more concise:

import List.Extra as List

someList |> List.filter (List.contains myList)

I can make a PR on this if my suggestion some kind of approval.

Transpose of jagged array

We need to decide on an appropriate way of handling non-rectangular arrays. As @gilberkennen wrote in #83, (some of) the possible options are...

  1. We could wrap the whole thing in a Maybe which fails on different-length lists.
  2. We could wrap individual elements in Maybe, which would be a bit awkward to deal with.
  3. We could truncate the matrix to the shortest list size, which seems a bit surprising, but less surprising than the current functionality and it gives us the nicer type that wouldn't need to change.

As of #83, the behavior aligns with the third option but the implementation can be easily adapted to any of them. The option that I am now leaning towards is to just say in the docs that the output for non-rectangular input is unspecified and can change at any time (although I can definitely see many arguments against that course of action related to maintainability). I am also strongly considering option number 1.

foldl/foldr rename

The foldl and foldr implementations in this package conflict with the default so both cannot be brought in at once. However the main thing is that many languages have both a foldl/foldr, which iterate while taking the default accumulator, but also have a reducel/reducer, which are foldl/foldr but they take the first element as the accumulator initial state if two elements, else return the first or empty list, basically what the List.Extra.foldl/foldr are doing now. Thus renaming them to be reducel/reducer would allow being able to import both List and List.Extra simultaneously for such functions. This would be a major version number change, but well worth it to get done early.

Why zipWith was removed?

Hi,
I notice that zipWith was removed long time ago. Is there a special reason for this?

Thanks!

Function to group by some property, and return tuples of the property and the sub-list

Thanks for this library, I use it all the time! I forked it and am trying to add a function "groupBy" to transform a List where each element has some shared comparable property like this:

list : List (Int, String)
list =
    [ (1, "a"), (1, "b"), (2, "c") ]

{-| Output:
    [ (1, [ (1, "a"), (1, "b") ] )
    , (2, [ (2, "c") ] )
    ]
-}
grouped : List (Int, List (Int, String))
grouped =
    List.Extra.groupBy fst list

I am having trouble because I am still pretty slow at functional programming and it feels like solving an incredibly arduous math problem, so I figured I'd at least make an issue in case someone else with more experience can do it easily.

Update Elm Test

@Chadtech FYI, a day or two before you adopted this, I pushed a quick fix to make Travis builds work for PRs again by constraining elm-test to v0.18.2 in .travis.yml.

At some point, you probably want to make tests work w/ the latest version of elm-test again.

Rename replaceIf or setAt

replaceIf and setAt are really two variants of the same kind of operation. They both replace some element(s) with a given value. Perhaps their naming should reflect this similarity. (Similar to how we have updateIf and updateAt.) Some questions to consider.

  1. Are there any advantages provided by keeping the current naming?
  2. If not, which name describes the operation better? (It may or may not be relevant to the discussion to note that Array uses the name set for a similar operation.)
  3. Perhaps out of the scope of this issue but also related, do we even need setAt and replaceIf when they are essentially equivalent to calling updateAt and updateIf with an update function of always x.

foldl1/foldr1 should use descriptive names as the '1' imparts no information

As requested by @jvoigtlaender this issue has been opened to propose changing the names (or at the very least aliasing the names to new names) of foldl1->reducel and foldr1->reducer or some variant there-of.

Immediate languages that come to mind that use this pattern are:

And I just found a document on wikipedia: https://en.wikipedia.org/wiki/Fold_(higher-order_function)#Folds_in_various_languages

On the above wikipedia list Haskell is the only language that uses foldl1 and foldr1, the general usage among the rest of the languages are various usages of reduce such as reducel/reducer, reduce_l/reduce_r, reduce_l/reduce_r, reduce/reduce_r, reduce/reduce_right and so forth with them using either another variant of reduce or using foldl/foldr to handle the Elm List.foldl and List.foldr style functions.

As seen reduce is used almost exclusively in languages that have a reduce/fold?1 style function, and both reduce and fold are used fairly evenly for fold style functionality depending on whether the language has default currying (like F# and Elm languages are) or whether the arity is part of the function definition (like Clojure or Elixir).

Thus to maintain consistency with the rest of near the entire functional ecosystem List.Extra.foldl1 and List.Extra.foldr1 should be at most renamed or at least aliased with List.Extra.reducel and List.Extra.reducer or some variant there-of as it is both more descriptive and functional language standard.

add rotateLeft and rotateRight

I think it would be good to add functions for rotating a matrix by 90 degrees. Here are possible implementations of the functions:

rotateLeft : List (List a) -> List (List a)
rotateLeft =
    List.reverse << transpose
rotateRight : List (List a) -> List (List a)
rotateRight listOfLists =
    List.foldl (List.map2 (::)) (List.repeat (rowsLength listOfLists) []) listOfLists

I omitted the helpers here for brevity, but made an Ellie with the full implementations and tests https://ellie-app.com/cyQ6L4kgta1/2. (Note that transpose and rowsLength are functions that I wrote that are already part of List.Extra.)

As for my use case, I was making a Tic-Tac-Toe game last night for fun and it turns out that having either of these functions make checking for a win very easy. Check it out! https://ellie-app.com/3zjbyv2y6a1/2 (scroll down to the checkStatus function).

One other thing worth discussing is the names. I do not think that the current ones make it clear that we are working with matrices and not 1-dimensional lists. For example, rotateRight [1, 2, 3, 4] might be misunderstood to be [4, 1, 2, 3] (which might also be a helpful function?).

Proposal for splitWhen function

It would combine the following function signatures:

findIndex : (a -> Bool) -> List a -> Maybe Int
splitAt : Int -> List a -> (List a, List a)

Here's a first stab at it:

splitWhen : (a -> Bool) -> List a -> Maybe ( List a, List a )
splitWhen predicate list =
    let
        index =
            findIndex predicate list
    in
        case index of
            Just i ->
                Just (splitAt i list)

            Nothing ->
                Nothing

groupWhile behaves like groupWhileTransitively

The docs for List.Extra.groupWhileTransitively state that it will "Start a new group each time the comparison test doesn't hold for two adjacent elements".

However, this is the behaviour that List.Extra.groupWhile exhibits, which does not seems consistent with its docs.

As far as I can tell the two functions behave identically, and the library provides no way to group together matching elements regardless of their position.

The code

module Main exposing (..)

import Html
import List.Extra

main =
    [ 0, 1, 1, 0, 0, 2, 3, 1 ]
        |> List.Extra.groupWhile (==)
        |> toString
        |> Html.text

Outputs [[0],[1,1],[0,0],[2],[3],[1]] rather than [[0,0,0],[1,1,1],[2],[3]]

Proposal for `maybeCons` function

I have found it useful when building views to be able to conditionally include an Attribute or child element. It seem natural to use Maybe to represent this conditional nature. However I usually only have one conditional attribute and several unconditional attributes so it feels a little awkward and overkill to wrap many elements in Just and then call filterMap identity. I would prefer to write the list literal and then conditionally add items.

maybeCons : Maybe a -> List a -> List a
maybeCons maybeItem list =
     case maybeItem of
          Just item -> item :: list
          Nothing -> list

For example when a tabbed container, I want to only attach click handlers to the non selected tabs to simplify my update logic.

let                                                                             
    (editOnClick, previewOnClick) =                                             
    case model.editorTab of                                                     
        Edit draft ->                                                           
            ( Nothing                                                           
            , Just <| onWithOptions                                                     
                "click"                                                         
                (Options True True)                                             
                (Json.Decode.succeed <| SetEditorTab <| Preview draft model.user.theme )
            )                                                                   
                                                                                
        Preview draft theme ->                                                  
            ( Just <| onWithOptions                                                     
                "click"                                                         
                (Options True True)                                             
                (Json.Decode.succeed <| SetEditorTab <| Preview draft model.user.theme )
            , Nothing                                                           
            )                                                                   
in                                                                              
    div [ id Editor ]                                                           
        [ div [ class EditorHeader ]                                            
            [ nav [ class HorizontalTabNav ]                                    
                [ button                                                        
                    ( maybeCons                                                 
                        editOnClick                                             
                        [ class HorizontalTab                                   
                        , action "/comments/edit" -- fallback for no JS, yeah yeah yeah XSS we handle it.
                        , method "post"                            
                        ]                                                       
                    )                                                           
                    [ text "Edit" ]                                       
                , button                                                        
                    ( maybeCons                                                 
                        previewOnClick                                          
                        [ class HorizontalTab                                   
                        , action "/comments/preview" -- fallback for no JS
                        , method "post"
                        ]                                     
                    )                                                           
                    [ text "Preview" ]                                             
                ]                                                               
            ]                                                                   
        , viewEditorTab                                                         
        ]

Cons

Haskell does not feel the need to implement this. It is really simple function anyone can write if they really need it.

Provide a stable sorting implementation

Elm's List.sortWith is implemented via Arrays.prototype.sort which is not guaranteed to be stable.

I'd like a stable sort for lists.

I have an implementation working based on porting the following Scheme code to Elm: http://www.scheme.com/tspl3/examples.html#./examples:h2.

Happy to make a pull request if this makes sense.

doSort : (m -> m -> Basics.Order) -> List m -> Int -> List m
doSort pred list n =
  if n == 1 then 
    List.take 1 list
  else
    let 
      i = n // 2
    in
      doMerge pred (doSort pred list i) (doSort pred (List.drop i list) (n - i))

doMerge : (m -> m -> Basics.Order) -> List m -> List m -> List m
doMerge pred l1 l2 =
  let 
    h1 = List.head l1
    h2 = List.head l2
  in
    case (h1, h2) of
      (Nothing, _) ->
        l2
      (_, Nothing) ->
        l1
      (Just h1', Just h2') ->
        if pred h2' h1' == Basics.LT then
          h2' :: (doMerge pred l1 (List.drop 1 l2))
        else
          h1' :: (doMerge pred (List.drop 1 l1) l2)

stableSortWith : (m -> m -> Basics.Order) -> List m -> List m
stableSortWith pred list =
  if List.isEmpty list then
    list
  else
    doSort pred list (List.length list)

Package hardwired to elm-core 4.0.0

I wanted to use this library but the library is hardwired to elm-core 4.0.0 (elm-core is currently at 4.0.1). My suggestion is that this library should make the dependancy on elm-core a bit more lenient.

andMap doesn't behave like an applicative apply

In most of the -extra packages where andMap appears (eg elm-community/elm-json-extra, elm-community/maybe-extra, elm-community/result-extra), it's documented to be applicative apply. In which case one would expect map f x and (pure f) |> andMap x to be the same (the "fmap law").

This isn't currently the case with list-extra (assuming pure x is [x] as usual):

> x = [1,2,3,4,5]
> d x = 2 * x
> List.map d x
[2,4,6,8,10] : List number
> [d] |> List.andMap x
[2] : List number

This seems counter-intuitive - is it intentional?

Upgrading tests

Elm 0.19 is out, and out tests stuff is all out of wack. Heres what needs to get done:

  • Upgrade the tests file for 0.19 (Done, thanks to @rlefevre )
  • Remove tests/.gitignore
  • Fix travis set up

We can probably wait until elm-test is past beta for fixing the travis stuff.

Permutation Memory Issues

In the slack channel, Numiastowski discovered that permutations causes a memory problem. A list of 9 elements might have as many as 9! permutations, and therefore, 9! stack calls.

I believe this can be solved by implementing something like this: https://www.nayuki.io/page/next-lexicographical-permutation-algorithm, or any non-recursive permutation function.

But before settling on that, we should consider use cases of the permutation function. Has anyone used it? How did you use it? What problem did it solve for you?

andMap's example is incorrect

The example uses the following code:

((\a b c -> a + b * c)
    |> map [1,2,3]
    |> andMap [4,5,6]
    |> andMap [2,1,1]
) == [9,7,9]

But it should be:

((\a b c -> a + b * c)
    |> flip map [1,2,3] -- change here
    |> andMap [4,5,6]
    |> andMap [2,1,1]
) == [9,7,9]

Proposal for more context in `groupWhile`

I recently came across the need for a version of groupWhile where the grouping function needs more context than just two adjacent elements.

Use-case

I am rendering the following messages in a chat-like layout:

messages =
  [ { receivedAt = 99, author = "Simon" }
  , { receivedAt = 100, author = "Maria" }
  , { receivedAt = 110, author = "Maria" }
  , { receivedAt = 120, author = "Maria" }
  , { receivedAt = 130, author = "Maria" }
  ]

Messages should be rendered closer together when they have a different author, but also if more than 15 time units elapse within a single group. The current groupWhile would put Maria's messages in the same group despite there being 30 time units between the first and the last message.

Proposed change to groupWhile

(or function under new name)

In the following type definition, both the previous member in the group as well as elements in the group before it show up in the grouping function (in the (List a, a) tuple):

groupWhile : ((List a, a) -> a -> Bool) -> List a -> List (a, List a)

Using this, I can group my messages for rendering as follows:

groupWhile
  (\( beforeInGroup, previous ) current ->
    previous.author == current.author &&
      (List.head beforeInGroup
        |> Maybe.withDefault previous
        |> .receivedAt
        |> (\receivedAt -> abs (receivedAt - current.receivedAt) < 15)
      )
  )
  messages

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.