OvermindDL1
Been making an MLElixir thing (not released yet…) for fun in spare time in the past day. I’m just trying to see how much I can get an ML-traditional syntax entirely within the Elixir AST, while being properly typed (with occasional fun with Refined Types and such). An example IEX session with it:
- Basic Types (adding more over time)
iex> import MLElixir
MLElixir
iex> defml 1
1
iex> defml 6.28
6.28
iex> defml :ok
:ok
- Let untyped variable bindings:
iex> defml let _a = 2 in 1
1
iex> defml let a = 1 in a
1
iex> defml let a = 42 in
...> let b = a in
...> let c = b in
...> c
42
- Let Typed variable bindings (The errors are very simplistic and not descriptive right now, still debugging time after all):
iex> defml let ![a: int] = 1 in a
1
iex> defml let ![a: float] = 6.28 in a
6.28
iex> defml let a = 1 in
...> let ![b: int] = a in
...> b
1
iex> defml let ![a: int] = 6.28 in a
** (MLElixir.UnificationError) Unification error between `{:"$$TCONST$$", :float, [values: [6.28]]}` and `{:"$$TCONST$$", :int, []}` with message: Unable to resolve mismatched types
(typed_elixir) lib/ml_elixir.ex:566: MLElixir.resolve_types!/3
(typed_elixir) lib/ml_elixir.ex:250: MLElixir.resolve_binding/3
(typed_elixir) lib/ml_elixir.ex:163: MLElixir.parse_let/3
(typed_elixir) expanding macro: MLElixir.defml/1
iex:16: (file)
- Let Refined Typed variable bindings:
iex> defml let ![a: int a=1] = 1 in a
1
iex> defml let ![a: int a<=2] = 1 in a
1
iex> defml let ![a: int a>=2] = 1 in a
** (MLElixir.UnificationError) Unification error between `{:"$$TCONST$$", :int, [values: [1]]}` and `{:"$$TCONST$$", :int, [values: [{2, :infinite}]]}` with message: Unable to resolve
(typed_elixir) lib/ml_elixir.ex:566: MLElixir.resolve_types!/3
(typed_elixir) lib/ml_elixir.ex:250: MLElixir.resolve_binding/3
(typed_elixir) lib/ml_elixir.ex:163: MLElixir.parse_let/3
(typed_elixir) expanding macro: MLElixir.defml/1
iex:6: (file)
Function calls (shown here via +):
iex> defml 1+2
3
iex> defml 1.1+2.2
3.3000000000000003
iex> defml 1+2.2
** (MLElixir.UnificationError) Unification error between `{:"$$TCONST$$", :int, [values: [1]]}` and `{:"$$TCONST$$", :float, [values: [2.2]]}` with message: Unable to unify types
(typed_elixir) lib/ml_elixir.ex:712: MLElixir.unify_types!/3
(typed_elixir) lib/ml_elixir.ex:108: anonymous fn/3 in MLElixir.Core.__ml_open__/0
(typed_elixir) lib/ml_elixir.ex:199: MLElixir.parse_ml_expr/2
(typed_elixir) lib/ml_elixir.ex:145: MLElixir.defml_impl/2
(typed_elixir) expanding macro: MLElixir.defml/1
iex:2: (file)
Opening (‘import’ in Elixir parlance) another module (also showing how to disable the Core opens, as you can see it is the Core that defines the + function):
iex> defml let open MLElixir.Core in 1+2
3
iex> defml no_default_opens: true, do: let open MLElixir.Core in 1+2
3
iex> defml no_default_opens: true, do: 1+2
** (MLElixir.InvalidCall) 6:Invalid call of `+` because of: No such function found
(typed_elixir) lib/ml_elixir.ex:196: MLElixir.parse_ml_expr/2
(typed_elixir) lib/ml_elixir.ex:145: MLElixir.defml_impl/2
(typed_elixir) expanding macro: MLElixir.defml/1
iex:6: (file)
Trending in Announcing
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries.
offset-based pagination with...
New
I needed to reuse React components from my Chrome extension in my Phoenix/LiveView backend. I noticed that for Svelte/Vue, there are live...
New
I released Doggo, a collection of unstyled Phoenix components.
https://github.com/woylie/doggo
Features
Unstyled Phoenix components....
New
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
Hi there! We created Gust: A task orchestrator inspired by Airflow.
For those who have never heard about Aiflow, it’s a Python-based wor...
New
Hello
Published a new library - ProcessHub!
ProcessHub is a library designed to manage process distribution within the Elixir cluster. ...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Other Trending Topics
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hi everyone!
The first release candidate for the Expert language server project is now available!
We’ve published a press release detai...
New
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself.
My main conc...
New
It’s not that it’s vocabulary is too advanced. It’s something worse.
I get lost trying to follow even a paragraph written by Claude. It’...
New
This showed up on my feed.. anyone heard of it? Just hype?
Ox Alpha is a reasoning model designed for coding, sustained ag...
New
Hey folks,
I just published a post about Hologram’s funding and where the project goes next - the short version:
Curiosum as Main Spons...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #security










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
OvermindDL1
Cannot come up with a good syntax for an anonymous function, I was hoping for
fun blah -> blah, especially as thatquotes well by becoming[{:->, [], [[{:fun, [], [{:blah, [], Elixir}]}], {:blah, [], Elixir}]}], but putting it in a file (even inside a quoted context) causes aCompileErrorofunhandled operator ->, which is irritating… what is unhandled about it?! I’m trying to handle it… blah…Similar separators are no good either, such as
=>…I wonder why the inconsistency between a
quote do fun blah -> blah endand asomeMacro(fun blah -> blah), wonder if this is an Elixir compiler bug…EDIT: Also, wtf does
fnrequire an end regardless of any internal content in a macro, blah… I’ll probably just usefn, though awfully elixir with the weird trailing ‘end’ for no reason (considering there is only a single expression inside it)… Really really badly hate trailing turds (to use an erlang expression) likeend’s for no reason though, even in Elixir… Whoever thought of (ruby creators? morons…) putting blocks in random places like an anonymous function with a single expression should go back to language design…I’d very much like another idea on how to do function definitions in elixir’s syntax. ^.^
ericmj
There is not an inconsistency. Maybe you think you are doing
fun(blah -> blah)but you are actually doingfun(blah) -> blah.->can only exist inside a block.quote do fun blah -> blah end← here the quote creates a block for you, but when you call a macro assomeMacro(fun blah -> blah)you don’t have create a block.Since the expression after
->is a block how do you know when to stop adding expressions to the block withoutend. For example:Since we don’t have an
endis the `IO.inspect part of the anonymous function or not?OvermindDL1
I also tried
defml(fun x -> x)with the same operator error. ^.^(EDIT: Also yesterday I tried this with an error too (
defmlsupports single expression or do syntax both):)
Exactly! The block should be explicit like it is everywhere else (with
do/end). fn by default should have been a single expression element with an optional block (potentially also viado/end). The → could just be an infix operator that defines the left as the arguments and the right as the single expression (of which that expression could be a block), kind of like:Explicit is better than implicit after all. ^.^
Also, wtf magical inconsistency? o.O
/me really hates magically appearing blocks
Although I may be slightly biased considering every language I’ve very often used in the past does not have magically appearing blocks, from:
{}, or leave it in many case for a single expression.<expr>;<expr>is basically alet _ = <expr> in <expr>, when you stop it the ‘block’ ends, but it is not really a block, just a list of delimited expressions.Etc…
ericmj
I don’t see why you would get an error there. I just tried this in iex and it worked.
What is the magical inconsistency? It works because
quote do fun blah -> blah endhas a block. Do you see thedo ... end?OvermindDL1
Uhh, really? o.O?
(EDIT: Urp, my mistake, used
fnhere instead offun, I’d preferfnbut it is less useful thanfundue to auto-block magicness.)Straight from one of my tests:
Uncommenting it results in:
Simplifying it to:
Results in an identical error.
Why yes, I see a block here:
And I get an
endmissing.And interestinyl replacing
defmlwithquoteto become:In the test file also fails with an identical error… o.O
Just commented those lines and the test file passes again so it is not the file causing the issue… Trying from iex now:
And yet trying to use the original syntax that I wanted:
Hmm, so quote takes this syntax fine, let’s dump it into defml then:
Hence here is the wtf. ^.^
EDIT: Think I may have come up with a fairly consistent way that gets rid of the
endoddness when you only have a single expression…Which brings up, is there a construct in elixir (not an anonymous function as those have overhead) where you can make a new variable bindings?
caseis apparently not it because it does a really stupid thing where:I think I’m just going to have to decorate every-single-variable with a trailing number or something… Some things in the Elixir AST just do not make sense >.<
ericmj
The difference between
quote do fun x -> x endanddefml fun x -> xis exactly the block.quoteis not magically cheating in any way, the parser accepts->inquotebecause it’s inside a block. When you call yourdefmlmacro you don’t wrap->in a block.If you use
fn x -> xinstead offun x -> xyou need to also end the block with anendsincefncreates a block just likedo.It’s easy to remember what creates blocks in Elixir because there are only three ways to do it.
do ... end,fn ... endand( ... ).doblocks are in fact just sugar for( ... )and they are represented the same way in the syntax tree.Check the “Blocks” section in the docs [1] for more details.
[1] https://hexdocs.pm/elixir/master/syntax-reference.html#syntax-sugar
OvermindDL1
The macro itself can wrap it though, it is just at the compiler level before the macro is ever hit… :-/
So… this?
So it does not seem like just sugar? O.o?
ericmj
The compiler raises with a syntax error which means it failed to parse the syntax. The parser does not expand macros or execute elixir code so it does not matter what you do in your macro. All code still has to be proper Elixir syntax regardless if we have macros.
Those are argument parenthesis. Try this:
defml((fun x -> x)).OvermindDL1
Was just about to edit my last post, already tried that.
Here is my edit content:
So it seems a function call does not scope inside it, this is such a weird syntax (I understand ‘how’ it is working the way it is, but not ‘why’ it was initially created this way…):
However, an issue here is the ‘:test_failed’ response that I am printing, that means it got
nilas the incoming AST, and indeed that is what I get for those if I print out my debug steps instead:And yet:
I’m… confused again… o.O
And for note, the
:MLtuple is the first thing listed:ericmj
Here’s your bug ^. Your macro receives something like:
ast = [{:->, [], [[{:fun, [], [{:x, [], Elixir}]}], {:x, [], Elixir}]}].ast[:do] == nilbecause you have no:doblock there.