Lisplog

Blogging in Lisp

Search

Feed Aggregator Page 689

Rendered on Mon, 28 Feb 2022 12:31:45 GMT  newer latest older 

Super-lightweight SVG identicon (avatar) generator

via Elm - Latest posts by @system system on Mon, 28 Feb 2022 09:55:31 GMT

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.

Keep cursor position and focus on input field while typing after a backend request

via Elm - Latest posts by @gorgoroth Gorgoroth on Mon, 28 Feb 2022 07:48:05 GMT

Okay. I have found the issue. Nothing to do with keyed elements.
The problem is mine. I’m using a loading view while loading data but obviously this view ‘erases’ the previous view every time. I need to manage the loading phase in a different way.

Tail recursion, but modulo cons

via Elm - Latest posts by @jfmengels Jeroen Engels on Mon, 28 Feb 2022 07:28:25 GMT

Tail recursion, but modulo cons

I worked on extending Elm’s tail call optimization so that it applies to more recursive functions. Hope you love the result as much as I do :heart:

NoEtaReducibleLambdas elm-review rule

via Elm - Latest posts by @robin.heggelund Robin Heggelund Hansen on Mon, 28 Feb 2022 02:32:49 GMT

The reason List.map (someFunction apple) bananas Is faster is because the curried call returns a single-arity function which will be executed directly by List.map, while List.map (\apples banana -> someFunction apples banana) bananas will have to create a curried version of the lambda (with F2, which has some overhead) and then List.map essentially calls two functions when executing (first the lambda through A2, then someFunction through A2).

NoEtaReducibleLambdas elm-review rule

via Elm - Latest posts by @jfmengels Jeroen Engels on Sun, 27 Feb 2022 21:53:55 GMT

Hey @john_s!

Very nice work! I know quite a few people are interested in this because I’ve seen asked a number of times whether this existed. Well now it does! :raised_hands:

You mention changing performance attributes, so I just want to mention that even the changes that this rule makes can have some performance impacts.

When they have multiple arguments, Elm functions are wrapped in a FX function (F2, F3, F4, …), and when functions are called with multiple argument, they are called with a AX function (A2, A3, A4, …). What the AX functions do is check whether the function to call is wrapped in a FX function of the same number (A2 and F2, A3 and F3, …). If it’s the case, then the function is called with the original functions like f(a, b, c, ...). If it isn’t, then the function will be called one argument at a time f(a)(b)(c)... until all the arguments are passed, which is noticeably slower for a function that is often called.

@robin.heggelund wrote a very nice series of articles on Elm performance, including one article explaining How Elm functions work, and its following articles explain how they got faster (links to those at the end of this article).

That means that List.map (\apples bananas -> someFunction milk apples bananas) list will be faster than List.map (someFunction milk) list. Of course, always benchmark instead of making a claim, so I wrote a benchmark.

For Elm 0.19.1, performance is faster with the curried version (I was very surprised to be honest, and I don’t know how to explain) by 5%-10%. However, when run with elm-optimize-level-2, the curried version is 3.5 times slower (according to this particular benchmark at least).

Of course, this rule can also have the opposite effect. when you have a function defined as someFunction a = \b -> ..., then having it called like List.map (someFunction 1) list should be more performant than List.map (\a -> someFunction 1 a) list. In this case, the rule would push towards the former version which would be a good thing.

These performance impacts is the reason why it didn’t explore this rule further. But I think that there are some cases where it’s always going to be okay or better (on a performance level, not in terms of personal preferences), like for \apples -> someFunction apples or \apples bananas -> someFunction apples bananas being reduced to someFunction.

I think I would see the value in having a setting for the rule that only reports errors when the performance can be estimated to be at least as good as the current version. I see at least 2 scenarios when it could do that:

  1. When the entire lambda can be reduced to a single variable name, like \apples -> someFunction applessoimeFunction (that said, this should be benchmarked)
  2. When the rule knows which wrapper the function uses. So if we have someFunction milk = \apples bananas -> ..., then we can simplify \apples bananas -> someFunction milk apples bananas to someFunction milk (and otherwise this should be left untouched). This information can be gathered by looking at the definitions of each function. When the information is missing (code from dependencies, or functions from arguments), then no error should be reported.

What do you think?

PS: What does “Eta” mean?

So I made this other game... (Nonaga)

via Elm - Latest posts by @stiff Stiff on Sun, 27 Feb 2022 19:17:58 GMT

Well you don’t have to stop here. Replacing players with

, currentPlayer : Player
, otherPlayer : Player

will give direct access to data necessary and simplify winning condition check.

NoEtaReducibleLambdas elm-review rule

via Elm - Latest posts by @john_s John Suder on Sun, 27 Feb 2022 16:32:30 GMT

I published a rule that can be used to enforce varying levels of function simplification
elm-review-reducible-lambdas. The default settings are probably a little more aggressive than most in the community would prefer. However, you may be able to tinker with the settings to find a useful sweet spot for your project and so I decided to share in case anyone finds this useful.

Conservative Settings

This example config will only reduce single argument lambdas that have single letter argument names (thanks to @Arkham for the argument name predicate suggestion).

Error

  • \a -> someFunction a will reduce to someFunction

Not Error

  • \apples -> someFunction apples due to argument name length
  • \a b -> someFunction a b due to multiple arguments.
config : List Rule
config =
    [ NoEtaReducibleLambdas.rule
        { lambdaReduceStrategy = NoEtaReducibleLambdas.OnlyWhenSingleArgument
        , argumentNamePredicate = \argumentName -> String.length argumentName == 1
        }
    ]

More Aggressive

These are the default settings. These may reduce a little too aggressively for most.

Error

  • \apples -> someFunction apples reduces to someFunction
  • \apples bananas -> someFunction apples bananas reduces to someFunction
  • \apples bananas -> someFunction milk apples bananas reduces to someFunction milk
  • \apples bananas -> fn (apples 15) bananas reduces to \apples -> fn (apples 15)

Not Error

  • \bananas -> fn (apples 15) bananas because removing the lambda would change performance attributes by immediately evaluating (apples 15).
config : List Rule
config =
    [ NoEtaReducibleLambdas.rule
        { lambdaReduceStrategy = NoEtaReducibleLambdas.RemoveLambdaWhenNoCallsInApplication
        , argumentNamePredicate = always True
        }
    ]

So I made this other game... (Nonaga)

via Elm - Latest posts by @axelbdt Axel on Sun, 27 Feb 2022 13:01:42 GMT

Thanks for the feedback!

I implemented your suggestion as follows:

type alias Player =
    { player : Color, tokens : Set Platform }


type alias Model =
    { currentPlayer : Color
    , turnPhase : TurnPhase
    , board : Board
    , players : List Player
    , lastMovedPlatform : Platform
    , selectedToken : Maybe Token
    , selectedPlatform : Maybe Platform
    }

In practice I have the following problems with this model:

  • I still can’t directly access a player’s tokens (like the Dict Color (Set Platform) would have).
  • It is more involved to can’t check if a platform is empty and I loose the constraint of “one token max on a platform”.
  • This introduces some additional nesting that makes the update a bit more complex.

The pros being:

  • This does seem to model the game better, with improved names and straightforward types.
  • It avoids the Dict wrangling which is quite nice, though.
  • Domain functions dealing with Player type are nice.

I am considering going back to a Dict Platform Color, but with nice helper functions to get a player’s set of tokens, move the token, etc… And see which I like better

This is clearly overthinking it, but well, I have time and the goal is to improve :slight_smile:

The updated code is here : https://ellie-app.com/gNx2FTFYR3za1

State of JS 2021 Results

via Elm - Latest posts by @system system on Sun, 27 Feb 2022 08:33:41 GMT

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.

Sequential function calls

via Elm - Latest posts by @avh4 on Sat, 26 Feb 2022 22:31:14 GMT

Ah, great :smiley:

This brings to mind another way you might want to consider organizing it where you make a pair for each card and then combine them instead of making a full set of cards and then copying the full set:

let
    makeCardPair card =
        [ initializeCards model.selectedCard card
        , initializeCards model.selectedCard card
        ]
        -- or instead you could use:
        -- List.repeat 2 (initializeCards model.selectedCard card)
in
List.concatMap makeCardPair model.cards

Good luck w/ your game!

Sequential function calls

via Elm - Latest posts by @Branquinho Pedro Gomes Branquinho on Sat, 26 Feb 2022 22:14:39 GMT

You nailed it. Can you read minds? Because you totally got my point haha :slight_smile:

Yeah, so I was trying to instantiate pair of cards, because I’m creating that old memory-game, in which one have to find the matching pairs of cards.

In the future, I plan to incorporate random positions to the cards.

So far, I managed to flip the cards, only.

You can check the entire project here Elm-FlippingCards, or the live version here.

Thank you.

Sequential function calls

via Elm - Latest posts by @avh4 on Sat, 26 Feb 2022 21:55:20 GMT

Hi!

I’m not sure if I completely understood what you’re trying to accomplish, so let me talk through it a little bit to make sure I understood…

Elm is pure, so “calling a function” doesn’t have side-effects. And Elm, unlike Haskell, also doesn’t have a Monad interface to represent side-effects. So there’s not going to be any purpose to calling a function multiple times unless you are using different arguments. I’m thinking in your examples, you want to produce some values, and then use the values multiple times?

In the case of the ul example, you want to end up with two displayed copies of each card? If so, I’d do it like this:

let
    cardViews = List.map (initializeCards model.selectedCard) model.cards
in
Html.ul []
    (List.concat [cardViews, cardViews])

In your initializeN example, f would return the same value on every call, right? So then you can use List.repeat (and in your example, f isn’t passed an argument, so it’s really just a value, not a “function”):

List.repeat 5 f

Or if there were some arguments to f:

List.repeat 5 (f arg1 arg2 arg3)

If I’m wrong about the above and you do want different input values passed to each call, then you’d use List.map if you have a list of input values, possibly with List.range if you need to create a list of indices

cardFromIndex : Int -> Card
cardFromIndex i = ...

List.map cardFromIndex (List.range 1 52)

or List.indexedMap if you have a list of input values and want indices.

Sequential function calls

via Elm - Latest posts by @Branquinho Pedro Gomes Branquinho on Sat, 26 Feb 2022 21:29:16 GMT

I would like to do a sequential call in a ul view-statement.

view model =
    div [ class "tarot" ]
        [ div [ id "counter" ]
            [ text "Counter: "
            , span [] [ text "0" ]
            , text " seconds"
            ]
        , h1 [ class "center" ] [ text "TAROT CARD GAME" ]
        , ul []
            (List.map (initializeCards model.selectedCard) model.cards)
            (List.map (initializeCards model.selectedCard) model.cards)
        ]

More exactly, in

ul []
   (List.map (initializeCards model.selectedCard) model.cards)
   (List.map (initializeCards model.selectedCard) model.cards)
]

How can I call a function n times in a row; or, more generally, call a sequence of different functions, as in a Do statement in Haskell?

As another example,

initializeN n f =
    let
        stop = 1
    in
        if stop <= n then
            **Do**
                 f                                           -- Call function
                 initializeN (decrement n) f   -- Recursion with decreased value

in which,

initializeN f 5

Would call f five times.

Keep cursor position and focus on input field while typing after a backend request

via Elm - Latest posts by @gorgoroth Gorgoroth on Sat, 26 Feb 2022 11:28:47 GMT

Unfortunately at the moment I don’t have the code at hand.

The part of the view for log entries is an ElmUI Column with three rows:

  • first row containing the filter input
  • second row containing the log entries list
  • the third row containing a link to load more log entries

It seems that the entire ElmUI column is removed. I removed the second row in Elm but the problem persists. So is not because of the list of entries being updated.
I added DOM breakpoints (removal, subtree modification, attributes modification) in each row but no break occurs.
Adding a DOM removal breakpoint in che ElmUI Column node, breaks so is the column which is removed.

But why?

Keep cursor position and focus on input field while typing after a backend request

via Elm - Latest posts by @ni-ko-o-kin Nikolaus Wettstein on Sat, 26 Feb 2022 09:13:07 GMT

It would be easier to help if you could share an example so we can reproduce the problem.

My guess is, that the input field is inside the view where the new data from the server is rendered. So separating the data for the input and the response data should solve the problem.

How do i defualt a date model variable to todays date

via Elm - Latest posts by @system system on Sat, 26 Feb 2022 08:02:28 GMT

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.

So I made this other game... (Nonaga)

via Elm - Latest posts by @stiff Stiff on Fri, 25 Feb 2022 20:35:28 GMT

In language I’d describe the game as two players having 3 pieces of their (red or black) color. So model like

Player = { color: Color, pieces: List Platform }

feels closer to this description and thus more natural and easy to use.

Multiple Debuggers on page?

via Elm - Latest posts by @ChristophP Christoph P on Fri, 25 Feb 2022 20:12:50 GMT

I added some info about those memory leaks to the issues justification for adding app.kill() · Issue #886 · elm/core · GitHub

Multiple Debuggers on page?

via Elm - Latest posts by @ChristophP Christoph P on Fri, 25 Feb 2022 20:06:46 GMT

Nice, thanks for the insights

Multiple Debuggers on page?

via Elm - Latest posts by @ChristophP Christoph P on Fri, 25 Feb 2022 20:06:26 GMT

Ah thanks, if only that got merged :slight_smile:

 newer latest older