gampleman / elm-review-derive

Generate code for json encoders/decoders, codecs, fuzzers, generators, and more

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Idea: virtual macro

gampleman opened this issue · comments

At the moment, the package takes a top-level (if elm-review gains type inference capabilities we could drop that limitation) Debug.todo "<some string>" calls to essentially call a function that is a Type -> AST and we provide a combinator library to build these kinds of functions.

From that perspective, the question naturally occurs if such a function could be parametrised by additional arguments? Or could there be more than 1 function Type -> AST?

We could answer these questions by providing a virtual module that has the ability to express these things. For instance:

view : Html msg 
view = 
    Codegen.fromHtml "<div class="foo"><input type="text /></div>"

could be then fed to a function String -> Type -> AST and result in:

view : Html msg
view =
   Html.div [ Html.Attributes.class "foo" ] 
       [ Html.input [ Html.Attributes.type_ "text" ] [ ]
       ]

Some other usecases

test : Test 
test =
   Codegen.testMonadicLaws SomeModule.succeed SomeModule.andThen

this one is interesting, since it suggests need to get have a Reference type (which would expose type information) and the ability to call other generators (i.e. to generate appropriate Fuzzers).

test1 : Test 
test1 =
   Codegen.testIndempotent SomeModule.function

test2 : Test 
test2 =
   Codegen.testRoundtrip SomeModule.encode SomeModule.decode

More on this theme.

type alias SomeType =
   { a : Int
   , b : String 
   }

toConsole : SomeType -> String
toConsole =
    Codegen.toStringConsoleSyntaxHighlighted

produces

toConsole : SomeType -> String
toConsole v =
    "{ " ++ Console.bold "a" ++ " = " Console.green (String.fromInt v.a) ++ "\n, " ++ Console.bold "b" ++ " = " ++ Console.red ("\"" ++ v.b ++ "\"") ++ "\n}"

Here this is similar in functionality to the existing Debug.todo idea, but serves to disambiguate different potential use cases from a Target -> String type.

Weirdness

One of the basic ideas in elm-review is that the code should compile before you feed it to elm-review. Since these functions proposed above are essentially just placeholders for our rule to hook into, this wouldn't work.

I think there are 2 options:

  1. We would publish a module that provides these but with phoney implementations.
  2. We ignore this assumption and hope for the best.

Next steps

I think the main unknown for me is how to evolve the existing API/library to allow for these in a convenient way.

Interesting idea!

Regarding

  1. We would publish a module that provides these but with phoney implementations.
  2. We ignore this assumption and hope for the best.

I'm not a fan of the second choice because it's difficult for the user to then know what code gen options there are or what parameters they take. That said, for the first choice, if the user has to install a package, why not include the module in elm-review-todo-it-for-me and then the user has to install it both in their elm-review elm.json and their normal elm.json?

I guess the secret 3rd choice is, maybe this effort is better spent improving IDE plugins to support hotkeys for these sorts of actions 😅

Hm. The finicky thing is that we also want the user to be able to program these kinds of macros themselves... which makes anything we bake in kind of tricky.

So perhaps the fake module would also need to be generated...

It seems like what we are on the verge of coming up with is a macro system but with the distinction that instead of the macros being run at compile time, they are run once at design time and replaced with the code they generated?

Yeah sort of. I hesitate with the word macro because clearly this is more of an ad hoc code generator which is not quite the same thing.

But I think if we want to make code generation a highly productive feature of Elm development, then having extensible and well documented machinery for it seems like the way to go.

Like using Debug.todo "" as the "generate code here" placeholder is a fun idea and its sort of obvious to users, but it's also kind of un-elm-like in that its rather implicit and multiple dispatch (i.e. what a Debug.todo will generate depends on the surrounding context). So in some ways having some more obvious and specific markers may actually make for a better experience in using the tool (we can definitely make better errors for instance if the user uses the code generator wrong).

Yeah that makes sense. Given this repo is called elm-review-todo-it-for-me though it might make sense to create a new repo to explore this idea? Then also you'll control the repo and I won't be slowing you down whenever you want to make a PR