elm-in-elm / compiler

Elm compiler written in Elm
https://elm-in-elm.github.io/compiler/
BSD 3-Clause "New" or "Revised" License
388 stars 24 forks source link

Document what elm/core kernel functions can be done in pure Elm #50

Open Janiczek opened 5 years ago

Janiczek commented 5 years ago

(EDITED after comments from Jakub)

Ideally we'd like to create an elm-in-elm/core package that does everything elm/core does but in pure Elm (without kernel modules). That won't be entirely possible but we can try and minimize the amount of "magic" Elm needs the underlying platform to support.

Go through all the kernel modules in elm/core and create a table, say in notes/elm-core.md or xls or whatever, documenting which of those can be done in pure Elm. ("Don't know" is OK too!)

In case of any doubts, ask here / in your PR / on Discord!

gampleman commented 5 years ago

You might want to specify a bit the constraints. For example you could do mathematical operations in pure Elm, if you don't care that they will be horrifically inefficient. But for any practical purpose you'd want the Kernel version. On the other hand for some of the data structures a pure Elm solution may be less of a trade off.

Janiczek commented 5 years ago

For the mathematical operations, I don't expect us to implement Peano arithmetic or something. We can keep the type Int = Int and overwrite stuff in the compiler, like the official compiler does.

I gues this is more of a "go through the kernel modules" than "go through the whole elm/core" type of ticket. So, I'm editing the original description to say that.

I'm not sure how more to make this ticket clearer. We can definitely talk about specific cases as they come up. (Either in a PR / this issue / on Discord)

Warry commented 5 years ago

Given that Core's Kernel can be imported from other libs (https://github.com/elm/browser/blob/master/src/Elm/Kernel/Browser.js), it means that we would have to completely split off from Elm packages.

Janiczek commented 5 years ago

Ideally we'd allow usage of the packages (download them and all) but have our overrides for each platform (as much Elm-only as possible to minimize the amount of non-Elm overrides needed per platform)

Janiczek commented 5 years ago

Link to some further discussion on Discord: https://ptb.discordapp.com/channels/578305644780716039/578305645824966669/602182350352285717

harrysarson commented 5 years ago
Core module Non-kernel Notes
Platform.Sub ?
Platform.Cmd ?
Array Slow Uses JsArray to be fast - needs more investigation.
Basics Impossible and slow Particularly tricky to get right is (==), slow comes from Bools.
Bitwise Impossible
Char Impossible We need toUpper, toLower, toLocaleUpper, toLocaleLower, toCode and fromCode.
Debug Impossible
Dict Already elm/core uses a custom type based red/black tree implementation.
List Possible The must be some subtulies here - possible relating to the [] syntax.
Maybe Already
Platform ?
Process ?
Result Already
Set Already Just uses Dicts.
String Slow An implement dertermined to avoid kernel code could use type String = List Char.
Task I doubt it Calls out to Elm.Kernel.Scheduler.
Tuple Already Very simple module.

Notes

j340m3 commented 2 years ago
Janiczek commented 2 years ago

@j340m3 Doesn't making && a normal function mean that you need to evaluate both arguments before passing them into that function? ie. shortcircuiting would not be there anymore?

j340m3 commented 2 years ago

@Janiczek My apologies. You're absolutely right, I overlooked that detail. In this implementation, I really doubt this would be shortciruiting. I'll experiment if shortcircuiting can be implemented in similar fashion to the Maybe-Monad.

The other idea I would propose is the usage of _:

(&&) : Bool -> Bool -> Bool
(&&) a =
    case a of
        False -> \_ -> False
        True -> id

Does anyone know if this would shortcircuit? The documentation says AFAIK "discards the input". Is the elm/compiler optimizing it then as shortcircuit?

Parser of Wildcard Wildcard -> AST.Source.PAnything -> AST.Canonical.PAnything The most notable difference in handling wildcards vs. variables is IMO here but I have to admit that I'm a bit clueless of the behaviour/role of the destruct mechanism. Here PVar and PAnything are used exactly the same way. Here they are handled differently but I believe this is not relevant for the execution.

j340m3 commented 2 years ago
type Bool = Bool BVal
type BVal 
    = True
    | False

true : Bool
true = Bool True

false : Bool
false = Bool False

(&&) : Bool -> Bool -> Bool
(&&) (Bool a) =
    case a of
        False -> \_ -> Bool False
        True -> id

Would shortcircuit certainly because the second argument is never destructured. It just means that everywhere a Bool has to be implemented, we will have to plug the "monad" inbetween (aka Box it)

Janiczek commented 2 years ago

We can check the shortcircuiting with Debug.log:

Screenshot 2021-11-04 at 15 41 12 Screenshot 2021-11-04 at 15 40 57

Unfortunately Ellie won't allow me to swap a different && instead of the basics one, and during work hours I don't have the time to go hacking elm/core on my machine :) In any case, functions won't ever short circuit:

Screenshot 2021-11-04 at 15 43 54

so our only hope is that binary operators have the ability to short circuit built-in.

I'll check this later with a custom binop :)

gampleman commented 2 years ago

Perhaps the question to ask is: how important is the fact of short-circuiting? I don't think in the context of Elm it makes much of a semantic difference; it has only two observable effects: performance will be different as well as Debug.log.

I don't think that the performance difference would even be very significant in most cases.