Looking through the Elixir source I see that multiplication is defined like this:
#spec (number * number) :: number
def left * right do
:erlang.*(left, right)
end
I wanted to make a ** function to do power as an exercise. However, when I try, I get an exception and I can't figure out how to do it correctly.
#spec (number ** number) :: number
def left ** right do
:math.pow(left, right)
end
Always throws an error like:
** (SyntaxError) iex:7: syntax error before: '*'
I tried making it a macro, using unquote, using :"**" instead of **. Not sure why this doesn't work...
Any ideas?
Binary operators are predefined in Elixir, meaning that the Elixir parser will only parse a bunch of operators (which, obviously, include *). You can see the list of operators roughly in this section of the parser. There are some "free" operators, that is, operators that Elixir is able to parse but that are not used by the language itself (e.g., <~>), but ** is not among them.
Just to show that parseable operators can do what you want:
defmodule MyWeirdOperators do
def left <~> right do
:math.pow(left, right)
end
end
import MyWeirdOperators
3 <~> 4
#=> 81.0
Elixir does not have a ** operator. You cannot define a new infix operator without changing and recompiling at least the Elixir parser and the Macro module.
Related
Does the Gallina language in Coq have a predefined operator that helps avoid parentheses like Haskell's $ or OCaml's ##?
If not, is there a conventional one that people define using Notation?
I didn't test this, but it should work for a lot of contexts:
Notation "f ## x" := (f x) (at level 10, x at level 100).
The gist of this is that we put the argument expression at the level 100 which is the highest level, meaning the parser kind of starts parsing the argument expression (x) as a standalone expression.
The level 10 is the level of function application, so you don't want to go below that because something like hd 41 ## [42; 43] wouldn't parse.
I am playing around with Elixir macros - specifically macros that call themselves which is something that I do often in Scheme. I have created a little test macro below however it just hangs iex - nothing is printed to console. Does anyone have any insight into why and what could be done to correct it?
defmodule RecMac do
defmacro test_rec(x) do
quote do
IO.puts("Started?")
if(unquote(x) < 1) do
IO.puts("Done?")
"done"
else
IO.puts("Where are we")
IO.puts(unquote(x))
RecMac.test_rec(unquote(x) - 1)
end
end
end
end
EDIT!!
OK, so it turns out you can define recursive macros where there is a structural difference to match on (eg lists). The following is working for me. And to confirm #Aleksei Matiushkin below, the above will not work and does indeed not work in scheme!
defmacro test_rec([h | t]) do
quote do
IO.inspect([unquote(h) | unquote(t)])
RecMac.test_rec(unquote(t))
end
end
defmacro test_rec([]) do
quote do
IO.puts "Done"
end
end
end
I am very happy to have dug into this as I learned something about two languages!
TL;DR: this is impossible.
Macros in elixir are not what you expect them to be. When a compiler sees a macro, it calls it during a compilation time and injects the AST it returned in the place of where it was called. That said, recursive macros would always lead to the infinite loop at the compilation stage.
Put IO.puts("something") before quote do instruction and you’ll see it to be printed infinitely, once per subsequent call to expand the macro.
You can use #compile {:inline, test_rec: 1} to achieve the behaviour you are after. For better understanding macros, you probably should read Macros section in the Elixir Guide in general and this excerpt in particular:
Macros are harder to write than ordinary Elixir functions and it’s considered to be bad style to use them when they’re not necessary. So write macros responsibly.
Actually you can do kind of recursion, but point is to think what you are doing to avoid calling macro inside quote do [....] end. Your example with IO.puts would be something like this
defmodule RecMac do
defmacro test_rec(list) do
{:__block__, [], quote_value(list)}
end
defp quote_value([]), do: []
defp quote_value([h | t]) do
if h < 1 do
[]
else
ast = quote do
IO.puts("#{unquote(h)}")
end
[ast | quote_value(t)]
end
end
end
you will notice two things, I do use recursion in macro but outside quote using private function quote_value/1 and that function has logic that "stops" after it finds value lower than 1. All "quotes" are put into list and trick is to put this list into tuple {:__block__, [], put_quote_list_here}
Now note that this macro wont compile if list parameter of test_rec is not know upfront (during compile time), so you need to call macro test_rec(["a", "b", 0, 100, 200]) so compiler knows size and elements of that list.
BTW, I used body optimized recursion, but you can easily add accumulator and convert this into tail optimized recursion.
I come from Scala. So I frequently do stuff like:
println((1 to 10).filter(_ < 3).map(x => x*x))
In Haskell, after I discovered I can get rid of all the nested parenthesis using $ and ., I recently found myself writing:
putStrLn . show . map (**2) . filter (< 3) $ [1..10]
Now, this works, but the code reads right-to-left, and unless I shift to Arabic, this is difficult for me to reason about.
Is there any other trick that makes me chain the functions from left to right? Or this is just the Haskell idiomatic way?
Unfortunately, it's the Haskell idiomatic way. But the & operator might do what you want.
import Data.Function ((&))
[1..10] & filter (< 3) & map (**2) & show & putStrLn
Essentially, (&) = flip ($). Likewise, Control.Arrow.(>>>) = flip (.)
UPDATE (6+ months later): I have to admit, this issue is a big source of frustration for me and I have been toying with this potential solution:
https://gist.github.com/obadz/9f322df8ba6c8a9767683d2f86af8589#file-directionalops-hs-L81
Yes, it is idiomatic Haskell. Not Arabic, but rather Mathematic, derived from the syntax for composition. See also Haskell composition (.) vs F#'s pipe forward operator (|>).
Still, even in Haskell you sometimes prefer to write your calls in the other direction, and you'll find a few libraries (e.g. Data.Function since base 4.8.0) who have defined
(&) = flip ($)
so that you can express your call as
[1..10] & filter (< 3) & map (**2) & show & putStrLn
Why not make a new operator?
(#) :: a -> (a -> b) -> b
(#) = flip id
Now you can just write
[1..10] # filter (< 3) # map (**2) # show # putStrLn
This is the equivalent of the (&) operator from Data.Function.
Suppose I have this macro definition in a module:
module Example
export #example_macro
macro example_macro(a)
quote
local r = RemoteRef()
put!(r, $(esc(a)))
remotecall_fetch(2, (r) -> fetch(r), r)
end
end
end
And here is its expansion:
julia> include("Example.jl")
julia> using Example
julia> macroexpand(quote #example_macro a end)
quote # none, line 1:
begin # /.../Example.jl, line 7:
local #121#r = Example.RemoteRef() # line 8:
Example.put!(#121#r,a) # line 9:
Example.remotecall_fetch(2,(r) -> Example.fetch(r),#121#r)
end
end
Every single one of globally available functions (like put! or fetch) are prefixed with the name of the module. I understand that this is needed for the macro to be hygienic - if, say, fetch was redefined in the module in which #example_macro is called, and fetch was inserted into the expansion as is, it wouldn't work correctly.
However, this also requires Example module to be available not only in the main process, but also on the second worker (since remotecall_fetch needs to execute Example.fetch on it). I don't want it - after all, fetch is a basic function available on all workers by default.
So, is there a way to disable prefixing all identifiers with the name of the current module? I think this would mean turning the macro non-hygienic as it is impossible to decide where some identifier (like fetch) is defined on macro expansion phase, and that's fine for me.
Since this is a pretty profound question, I think that you should give the Julia devs themselves a chance to answer it by asking on julia-users.
Currently, you can completely circumvent macro hygiene by wrapping the whole quote block in your macro in an esc(...) (don't forget to take away the esc around a), but I would in general advise against it - then you are on your own.
This is a pattern of optimization in Lisp code that I want to achieve in Red:
(defmacro compute-at-compile (x)
`(+ ,(* pi 2) ,x))
(macroexpand '(compute-at-compile 1))
; => (+ 6.283185307179586 1)
How do I express this in Red? (I realize it may not be possible in today's implementation, I'm wondering about how one would express the code at the language level to get such an optimization. Would it require special markup in the source, or would it be automatic like Lisp?)
Trying to extend my answer to maybe cover another idea that may help you find what you are looking for.
Red/System
From my understanding, the Red/System #define directive can help with optimization (in reducing function calls). Here is a similar example in Red/System. Within Red, it would require using within #system or #system-globaldirective.
#define COMPUTE(x) (3.13159 * 2.0 + x)
b: COMPUTE(1.0)
print b
Processing the macro should result in:
b: (3.13159 * 2.0 + 1.0)
print b
and results
7.26318
Math between types isn't defined yet, so you'll run into issues multiplying/adding float! and integer! (hence the above use of float!)
Red/Rebol
You can also take a look at compose as a higher level way to optimize your code writing. I am unsure of the effect in terms of optimizing speed. What compose does is take a block and evaluate whatever is in parenthesis and not evaluate other elements in the block.
See the Rebol2 help definition for compose
>> help compose
USAGE:
COMPOSE value /deep /only
DESCRIPTION:
Evaluates a block of expressions, only evaluating parens, and returns a block.
COMPOSE is a native value.
ARGUMENTS:
value -- Block to compose (Type: any)
REFINEMENTS:
/deep -- Compose nested blocks
/only -- Inserts a block value as a block
This may be what you're looking for in terms of building expressions
red>> x: 1
== 1
red>> compose [3 + 2 + (x)]
== [3 + 2 + 1]
An example from the Rebol2 documentation:
>> probe compose [time: (now/time) date: (now/date)]
[time: 12:48:53 date: 5-Mar-2014]
== [time: 12:48:53 date: 5-Mar-2014]