41

Is there any way to define an Erlang function from within the Erlang shell instead of from an erl file (aka a module)?

2240
  • 1,547
  • 2
  • 12
  • 30
yazz.com
  • 57,320
  • 66
  • 234
  • 385
  • From Erlang/OTP 26, you can define functions directly in the shell: https://www.erlang.org/blog/otp-26-highlights/#the-shell – 2240 May 17 '23 at 12:56

4 Answers4

46

Yes but it is painful. Below is a "lambda function declaration" (aka fun in Erlang terms).

1> F=fun(X) -> X+2 end.
%%⇒ #Fun <erl_eval.6.13229925>

Have a look at this post. You can even enter a module's worth of declaration if you ever needed. In other words, yes you can declare functions.

Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
jldupont
  • 93,734
  • 56
  • 203
  • 318
  • 1
    Thanks, that worked. Do you know why the functions cannot be defined in the same way as they are in an erl file. Is it because "eval"ed code cannot "receive"? (I'm new to erlang so please correct me if what I am saying sounds like gibberish) – yazz.com Jan 14 '10 at 17:20
  • The example above is really a "lambda function declaration". Have a look at the articles I have linked in my answer: explanation is extensive. – jldupont Jan 14 '10 at 17:24
  • I'm looking through those links now. Its starting to make sense :) – yazz.com Jan 14 '10 at 18:24
  • You can put a receive statement inside a fun. – Adam Lindberg Jan 14 '10 at 20:25
  • When you start the console you start up a separate VM. An Erlang VM can no more receive on its own than a Java VM can. In a Java VM a class contains the code that receives. In an Erlang VM a function contains the code that receives. It isn't quite as REPL as Python or Ruby, but that isn't a bad thing once your thinking changes. – Jeffrey Hulten Jan 16 '10 at 21:36
  • 5
    The shell process is a normal process with a Pid that you can send messages to. You can start an Erlang console and write a receive loop, and send to that process from another process you spawned, or from another Erlang node. – bjnortier Aug 20 '10 at 12:28
18

One answer is that the shell only evaluates expressions and function definitions are not expressions, they are forms. In an erl file you define forms not expressions.

All functions exist within modules, and apart from function definitions a module consists of attributes, the more important being the modules name and which functions are exported from it. Only exported functions can be called from other modules. This means that a module must be defined before you can define the functions.

Modules are the unit of compilation in erlang. They are also the basic unit for code handling, i.e. it is whole modules which are loaded into, updated, or deleted from the system. In this respect defining functions separately one-by-one does not fit into the scheme of things.

Also, from a purely practical point of view, compiling a module is so fast that there is very little gain in being able to define functions in the shell.

rvirding
  • 20,848
  • 2
  • 37
  • 56
  • Could you explain the difference between functions and forms? – yazz.com Jan 21 '10 at 06:10
  • 4
    Form is the name we gave to what you can have in a module file. So forms are both the attributes in a file, -module(), -export(), etc, and the function definitions. These are **not** expressions in that they are not evaluated and do not return values. We gave them the name forms so as to disinguish them from expressions. – rvirding Jan 21 '10 at 21:39
5

This depends on what you actually need to do.

There are functions that one could consider as 'throwaways', that is, are defined once to perform a test with, and then you move on. In such cases, the fun syntax is used. Although a little cumbersome, this can be used to express things quickly and effectively. For instance:

1> Sum = fun(X, Y) -> X + Y end.
#Fun<erl_eval.12.128620087>
2> Sum(1, 2).
3

defines an anonymous fun that is bound to the variable (or label) Sum. Meanwhile, the following defines a named fun, called F, that is used to create a new process whose PID (<0.80.0>) is bound to Pid. Note that F is called in a tail recursive fashion in the second clause of receive, enabling the process to loop until the message stop is sent to it.

3> Pid = spawn(fun F() -> receive stop -> io:format("Stopped~n"); Msg -> io:format("Got: ~p~n", [Msg]), F() end end). 
<0.80.0>
4> Pid ! hello.
hello
Got: hello
5> Pid ! stop.
Stopped
stop
6> 

However you might need to define certain utility functions that you intend to use over and over again in the Erlang shell. In this case, I would suggest using the user_default.erl file together with .erlang to automatically load these custom utility functions into the Erlang shell as soon as this is launched. For instance, you could write a function that compiles all the Erlang files in living in the current directory.

I have written a small guide on how to do this on this GitHub link. You might find it helpful and instructive.

Duncan Paul
  • 485
  • 5
  • 13
4

If you want to define a function on the shell to use it as macro (because it encapsulates some functionality that you need frequently), have a look at

https://erldocs.com/current/stdlib/shell_default.html

Maqbool
  • 197
  • 2
  • 9