GithubHelp home page GithubHelp logo

mgold / elm-nonempty-list Goto Github PK

View Code? Open in Web Editor NEW
46.0 46.0 9.0 176 KB

head and tail without the Maybe

Home Page: http://package.elm-lang.org/packages/mgold/elm-nonempty-list/latest/List-Nonempty

License: BSD 3-Clause "New" or "Revised" License

Elm 100.00%

elm-nonempty-list's People

Contributors

bobwhitelock avatar emilgoldsmith avatar mgold avatar newmana avatar timjs avatar

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

Watchers

 avatar  avatar  avatar

elm-nonempty-list's Issues

Feature request - A function to group elements in a Non-empty list

The elm-community/lists-extra package features a function called groupWhile which is handy for going from a List a to a List (List a) with like elements being grouped together into sub-lists; where like-ness is determined by a function of signature a -> a -> Bool.

I would like to see such a function implemented for non-empty lists. I've implemented the function as shown below. As to it's correctness... I suppose that's debatable :)

An implementation

Here's my idea for an implementation. Note, the like the equivalent function in List.Extras, this one may produce unexpected results if the list is not sorted first.

import List.Nonempty as NE exposing (..)
import Html exposing (text)


{-| Groups the elements in the non-empty list using the predicate.
NOTICE: You may want to sort the list first.

    import List.Nonempty as NE

    [1, 1, 2, 3, 3]
        |> NE.fromList
        |> Maybe.map (groupWhile (==))
        |> Maybe.withDefault []

        -- Result is [[1, 1], [2], [3, 3]]
-}
groupWhile : (a -> a -> Bool) -> Nonempty a -> Nonempty (Nonempty a)
groupWhile predicate list =
    let
        seed : Nonempty (Nonempty a)
        seed =
            head list
                |> fromElement
                |> fromElement

        folder : a -> Nonempty (Nonempty a) -> Nonempty (Nonempty a)
        folder current groups =
            let
                group : Nonempty a
                group =
                    head groups
            in
                if all (predicate current) group then
                    Nonempty (fromElement current |> append group) (tail groups)
                else
                    (fromElement current) ::: groups
    in
        case list of
            Nonempty a [] ->
                fromElement list

            Nonempty a (x :: xs) ->
                foldl folder seed (Nonempty x xs)
                    |> NE.reverse

Implementation description

Because the list is not empty, the grouping process begins by creating the first group using the head of the list. If the list only contains one element, then the group is returned, and that's the end of it. Otherwise, the tail --which is guaranteed to have at least one element-- is turned into a non-empty list and the folding begins.

If the predicate signifies that adjacent elements are alike, then they are grouped together.

Finally, because new groups are added to the front of the list, the final step is to reverse the list so that the original ordering is preserved; though nested into sub-lists.

Add `asNonempty` for functions designed for (head, [tail]) output

Found myself writing this code today when reaching for a List.Extra utility that outputs a nonempty list in the dependency-free style. I prefer to use this library, so:

List.gatherEqualsBy Object.eventReference eventsList
                |> (\( h, t ) -> Nonempty h t)

But the latter function would be a great inclusion in this package, taking any (x, xs) function and converting it to output Nonemptys.

order of operands to `append`

The documentation for append does not specify which list is appended to which. Normally in Elm, we put the data structure being operated on last, so that we can do

list1
    |> List.Nonempty.append list2

Since this seems not to be the case here, it should perhaps be documented.

Wouldn't it make more sense to call the main type NonEmptyList?

TLDR

I want to write:

import List.Nonempty exposing (NonEmptyList)

things : NonEmptyList Thing

Long explanation

Hey! Thanks for this useful package. I hope you won't find this too much of nitpicking. If you do, feel free to ignore the issue.

Maybe I'm missing something, but when I use this package I import it like this:

import List.Nonempty

Then if I want to annotate something I have to type:

things : List.Nonempty.Nonempty Thing

That's long and cumbersome. Alternatively I could expose the type:

import List.Nonempty exposing (Nonempty)

things : Nonempty Thing

But that's confusing. Now this annotation doesn't tell me what kind of collection is non-empty.

The current name of the type would only make sense if I would "merge" the import with the core List module, like this:

import List.Nonempty as List

things : List.Nonempty Thing

But that's not even possible because of clashing names (map, filter etc.). Also I wouldn't really want that, as non-empty list has different semantics.

So what I end up doing every time is:

import List.Nonempty

type alias NonEmptyList a =
    List.Nonempty.Nonempty a

things : NonEmptyList Thing

So why shouldn't I be able to write it like below?

import List.Nonempty exposing (NonEmptyList)

things : NonEmptyList Thing

I can make a PR if you want. To avoid a breaking change we could start with aliasing the type, so old code would still work.

Does it make sense? Am I missing something?

Add List.Nonempty.last

It would be nice to have the following function since it's guaranteed to not return Maybe

{-| Return the last element of the list.
-}
last : Nonempty.Nonempty a -> a
last nonempty =
    Nonempty.tail nonempty |> List.Extra.last |> Maybe.withDefault (Nonempty.head nonempty)

The List.Extra.last function can be found here. Probably best to copy the source code to avoid adding a dependency to elm-community/list-extra.

Error using this library as a dependency.

Just following instructions from the compiler.

Here's the error I get from elm-make:

Problem in dependency mgold/elm-nonempty-list 2.0.0                 

The elm-package.json constraints of 'mgold/elm-nonempty-list' are probably
letting too much stuff through. Definitely open an issue on the relevant github
repo to get this fixed and save other people from this pain.

In the meantime, take a look through the direct dependencies of the broken
package and see if any of them have had releases recently. If you find the new
thing that is causing problems, you can artificially constrain things by adding
some extra constraints to your elm-package.json as a stopgap measure.


Detected errors in 1 module.

Here's my elm-package.json:

{
    "version": "1.0.0",
    "summary": "helpful summary of your project, less than 80 characters",
    "repository": "https://github.com/user/project.git",
    "license": "BSD3",
    "source-directories": [
        "."
    ],
    "exposed-modules": [],
    "dependencies": {
        "NoRedInk/elm-check": "3.0.0 <= v < 4.0.0",
        "circuithub/elm-list-extra": "3.10.0 <= v < 4.0.0",
        "deadfoxygrandpa/elm-test": "3.1.1 <= v < 4.0.0",
        "elm-lang/core": "3.0.0 <= v < 4.0.0",
        "mgold/elm-nonempty-list": "2.0.0 <= v < 3.0.0"
    },
    "elm-version": "0.16.0 <= v < 0.17.0"
}

I looked at your elm-package.json and the only thing you depend on is elm-lang/core. And that hasn't changed. Any ideas here?

List.Nonempty.filter is misleading

I expected List.Nonempty.filter to have this type signature (a -> Bool) -> Nonempty a -> List a or (a -> Bool) -> Nonempty a -> Maybe (Nonempty a) but instead it has (a -> Bool) -> a -> Nonempty a -> Nonempty a.

I don't think this is a good idea because it's difficult to tell if all the items got filtered. If someone does want that behavior, it's easy for them to write List.Nonempty.filter condition nonempty |> Maybe.withDefault default instead (assuming the second type signature was used for filter).

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.