CarlosHSF

CarlosHSF

How to identify an AST node as a function call?

I’m trying to identify function calls. My current solution seems to be working, but I’m not sure what are the edge cases I should test for and I imagine there’s a better solution.

So far I determine a node is a function call if it is a triple, it’s third element is a list and it is not a special form.
So this {:foo, [], []} would be a function call, but this {:{}, [], []} wouldn’t and neither would this {:foo, [], nil}.

The code:

  # for functions calls or special forms with the same structure
  defmacro foo({call, _meta, args}) when is_list(args) do
    if Macro.special_form?(call, length(args)) do
      # do stuff if it ISN'T a function call
    else
      # do stuff if it IS a function call
    end
  end

  # for literals and variables
  defmacro foo(node) do
    # do stuff if it ISN'T a function call
  end

If you see any errors or know a better solution your help would be greatly appreciated!

Most Liked

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Hey @CarlosHSF to my knowledge this is roughly correct, but it’s also worth noting that it can’t distinguish between a macro call and a function call as, at an ast level at least, they are identical. You’ll also have to decide how you want to handle things like apply/3.

Last Post!

CarlosHSF

CarlosHSF

I’m trying to create a recursive block to allow for explicit recursion without the need to define a function or use ugly “recursive” anonymous functions. It is not meant to define a recursive function, only use recursion, just like a for loop for iteration in an imperative language. This is for a package I’m writing, Recurse.

Here’s an example of what I’m trying to do:

# factorial function expressed with a named recurse block
recurse fact(3) do
  0 -> 1
  n -> n * fact(n - 1)
end

# factorial function expressed with an unnamade recurse block
recurse 3 do
  0 -> 1
  n -> n * recurse(n - 1)
end

Both evaluate to 6.

Achieving something that does this was quite simple and that’s why I choose to keep the question simple instead of giving the whole context. But there many nuances that complicate making it robust and actually correct, that I’ve only now started to realize and make me doubt that what I’m trying to achieve is actually a good idea…

Currently, with what is in the package, it would be done like this:

recurse on 3 do
  0 -> 1
  n -> n * recurse(n - 1)
end

on is a second keyword to allow for multiple arguments to be given to recurse, but I would like to remove it as it doesn’t really make sense to have two keywords doing one job. There’s also the option of passing a tuple to give multiple arguments without a second keyword, but I’m trying to achieve something a bit more elegant.

So I thought I would allow the user to choose a name for the recursive call instead of just having on there, so instead of removing the second keyword, I would give it a purpose. Or the user could not choose any name and just use recurse as the recursive call, knowing that then they could only pass one argument or multiple in a tuple.

My problem then, is distinguishing if what follows recurse is a function call or not. There’s also the problem of it possibly being a function call, but one that should be evaluated and not used to create a named recursive call, but I’m ignoring that fact for the moment and once this is working and I’ve experimented with it I would decide if it is a decent idea or not.

Where Next?

Popular in Questions Top

nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New

Other popular topics Top

Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New

We're in Beta

About us Mission Statement