Not able to print a variable inside a recursive loop function - functional-programming

I am trying to implement this very simple counter, where every time I calling my method it should increment and print it. But for some reason, it increments the counter but doesn't print it.
defmodule Node2 do
def start() do
initial = 0
loop(initial)
end
def loop(counter) do
receive do
{:rumor, msg, from} ->
IO.puts "#{msg} received from :"
IO.inspect from
counter = counter + 1
IO.puts "Value of a Counter:"
IO.puts counter
loop(counter)
{:get_counter, msg, from} ->
IO.puts "Counter Value"
end
end
def send_rumor(to_pid, from_pid, msg) do
IO.puts "Send_rumor function!"
send(to_pid, {:rumor, msg, from_pid})
end
end
And my client method which calls it is defined as follows:
pid = spawn(fn -> Node2.start() end)
Node2.send_rumor(pid, self(), "Hello Sir!")
And the output is as follows:
Send_rumor function!
Hello Sir! received from :
#PID<0.77.0>
Value of a Counter:
It doesn't show the value of counter and prints blank.
But strangely when I make this little change to code, where I just print the variable initial in the start function, it gives me the output correctly.
def start() do
initial = 0
IO.puts initial
loop(initial)
end
New Output :
Send_rumor function!
0
Hello Sir! received from :
#PID<0.77.0>
Value of a Counter:
1
I am new to Elixir, and so not really sure what is going on here?

Related

Returning values from elixir functions inside modules

This is the method that processes an input string
def process(input) do
list=String.split(input, "\n")
f3=fn(a) ->
String.split(a," ")
end
list=Enum.map(list, f3)
func3=fn(n) ->
length(n)==3
end
func2=fn(n) ->
length(n)<=2
end
system=for x <-list, func3.(x), do: x
input=for y <- list, func2.(y), do: y
input=Enum.slice(input,0..length(input)-2)
output=""
output(input,output, system)
end
This is the output function that uses recursion to edit a string and eventually return its value
def output(input, output, system) do
cond do
length(input)==0 ->
output
true ->
[thing|tail]=input
if length(thing)==2 do
output=output<>"From "<>Enum.at(thing, 0)<>" to "<>Enum.at(thing,1)<>" is "<>Integer.to_string(calculate(thing, system))<>"km\n"
output(tail, output, system)
end
if length(thing)==1 do
if Enum.at(thing,0)=="Sun" do
output=output<>"Sun orbits"
output(tail, output, system)
else
output=output<>orbits(thing, system)<>" Sun"
output(tail, output, system)
end
end
output(tail, output, system)
end
end
As you can see when the input is an empty list it should return the output string. Using inspect shows that the output string does indeed have the correct value. Yet when the function is called in process(), it only returns the empty string, or nil.
Any help is appreciated, I am new to elixir so apologies if my code is a bit messy.
This could be a case where using pattern matching in the function head will let you avoid essentially all of the conditionals. You could break this down as:
def output([], message, _) do
message
end
def output([[from, to] | tail], message, system) do
distance = Integer.to_string(calculate(thing, system))
new_message = "#{message}From #{from} to #{to} is #{distance} km\n"
output(tail, new_message, system)
end
def output([["Sun"] | tail], message, system) do
output(tail, "Sun orbits #{message}", system)
end
def output([[thing] | tail], message, system) do
new_message = "#{message}#{orbits([thing], system)} Sun"
output(tail, new_message, system)
end
This gets around some of the difficulties highlighted in the comments: reassigning output inside a block doesn't have an effect, and there aren't non-local returns so after an if ... end block completes and goes on to the next conditional, its result is lost. This will also trap some incorrect inputs, and your process will exit with a pattern-match error if an empty or 3-element list winds up in the input list.
I've renamed the output parameter to the output function to message. This isn't required – the code will work fine whether or not you change it – but I found it a little confusing reading through the function whether output is a function call or a variable.

F# events not working inside Async workflow

I want to do a Post-Fire-Reply to an agent. Basically the agent triggers an event then replies to the caller. However I either keep getting a timeout error or the events do not fire correctly. I tried doing Post-Fire, that stopped the timeout errors but the events do not fire.
let evt = new Event<int>()
let stream = evt.Publish
type Agent<'T> = MailboxProcessor<'T>
type Fire = Fire of int
let agent = Agent.Start(fun inbox ->
let rec loop() = async {
let! msg = inbox.Receive()
let (Fire i) = msg
evt.Trigger i }
loop())
let on i fn =
stream
|> Observable.filter (fun x -> x = i)
|> Observable.filter (fun x -> x <> 1)
|> Observable.subscribe (fun x -> fn x)
let rec collatz n =
printfn "%d" n
on n (fun i ->
if (i % 2 = 0) then collatz (i/2)
else collatz (3*n + 1)) |> ignore
agent.Post (Fire n) // this does not work
// evt.Trigger n // this does works
collatz 13
This is a simple experiment that repeatedly creates a function to find the next number in the Collatz series and then calls itself to return the value until it reaches 1.
What seems to happen is that the trigger only fires once. I tried experimenting with every combination of Async.RunSynchronously / Async.Start / StartChild / SynchronizationContext that I could think of but no progress. I found a blog similar to what I am doing but that didn't help me neither
EDIT
Thank you Fyodor Soikin for pointing out my oversight. The original problem still remains in that I wish to both fire events and reply with a result, but get a timeout.
let evt = new Event<int>()
let stream = evt.Publish
type Agent<'T> = MailboxProcessor<'T>
type Command =
| Fire of int
| Get of int * AsyncReplyChannel<int>
let agent = Agent.Start(fun inbox ->
let rec loop() = async {
let! msg = inbox.Receive()
match msg with
| Fire i -> evt.Trigger i
| Get (i,ch) ->
evt.Trigger i
ch.Reply(i)
return! loop() }
loop())
let on i fn =
stream
|> Observable.filter (fun x -> x = i)
|> Observable.filter (fun x -> x <> 1)
|> Observable.subscribe (fun x -> fn x)
let rec collatz n =
printfn "%d" n
on n (fun i ->
if (i % 2 = 0) then collatz (i/2)
else collatz (3*n + 1)) |> ignore
agent.PostAndReply (fun ch -> (Get (n, ch))) |> ignore // timeout
agent.PostAndAsyncReply (fun ch -> (Get (n, ch))) |> Async.Ignore |> Async.Start // works but I need the result
agent.PostAndAsyncReply (fun ch -> (Get (n, ch))) |> Async.RunSynchronously |> ignore // timeout
collatz 13
Your loop function doesn't loop. It receives the first message, triggers the event, and then just... exits. Never attempts to receive a second message.
You need to make that function work continuously: process the first message, then go right back to receive the next one, then go receive the next one, and so on. Like this:
let agent = Agent.Start(fun inbox ->
let rec loop() = async {
let! msg = inbox.Receive()
let (Fire i) = msg
evt.Trigger i
return! loop() }
loop())
Edit
Since you've reached your limit on questions, I will answer your edit here.
The reason you're getting timeouts in your second snippet is that you have a deadlock in your code. Let's trace the execution to see that.
THREAD 1: The agent is started.
THREAD 2: The first collatz call.
THREAD 2: The first collatz call posts a message to the agent.
THREAD 1: The agent receives the message.
THREAD 1: The agent triggers the event.
THREAD 1: As a result of the event, the second collatz call happens.
THREAD 1: The second collatz call posts a message to the agent.
THREAD 1: The second collatz call starts waiting for the agent to respond.
And this is where the execution ends. The agent cannot respond at this point (in fact, it cannot even receive the next message!), because its instruction pointer is still inside evt.Trigger. The evt.Trigger call hasn't yet returned, so the loop function hasn't yet recursed, so the inbox.Receive function hasn't yet been called, so the second message is still waiting in the agent's queue.
So you get yourself a classic deadlock: collatz is waiting for the agent to receive its message, but the agent is waiting for collatz to finish handling the event.
The simplest, dumbest solution to this would be to just trigger the event asynchronously:
async { evt.Trigger i } |> Async.Start
This will make sure that the event handler is executed not "right there", but asynchronously, possibly on a different thread. This will in turn allow the agent not to wait for the event to be processed before it can continue its own execution loop.
In general though, when dealing with multithreading and asynchrony, one should never call unknown code directly. The agent should never directly call evt.Trigger, or anything else that it doesn't control, because that code might be waiting on the agent itself (which is what happened in your case), thus introducing the deadlock.

Writing the function "once" in Elixir

I'm coming to Elixir from primarily a Javascript background. in JS, it's possible to write a higher order function "once" which returns a function that will invoke the passed in function only once, and returns the previous result on subsequent calls- the trick is manipulating variables that were captured via closure:
var once = (func) => {
var wasCalled = false, prevResult;
return (...args) => {
if (wasCalled) return prevResult;
wasCalled = true;
return prevResult = func(...args);
}
}
It seems to me that it's not possible to create this function in Elixir, due to its different variable rebinding behavior. Is there some other clever way to do it via pattern matching or recursion, or is it just not possible? Without macros that is, I'd imagine those might enable it. Thanks
Using the current process dictionary:
defmodule A do
def once(f) do
key = make_ref()
fn ->
case Process.get(key) do
{^key, val} -> val
nil ->
val = f.()
Process.put(key, {key, val})
val
end
end
end
end
Or if the function will be passed across processes, an ets table can be used:
# ... during application initialization
:ets.new(:cache, [:set, :public, :named_table])
defmodule A do
def once(f) do
key = make_ref()
fn ->
case :ets.lookup(:cache, key) do
[{^key, val}] -> val
[] ->
val = f.()
:ets.insert(:cache, {key, val})
val
end
end
end
end
Application.put_env / Application.get_env can also be used to hold global state, though usually is used for configuration settings.
It's not considered idiomatic in most cases, but you can do this with Agent:
defmodule A do
def once(fun) do
{:ok, agent} = Agent.start_link(fn -> nil end)
fn args ->
case Agent.get(agent, & &1) do
nil ->
result = apply(fun, args)
:ok = Agent.update(agent, fn _ -> {:ok, result} end)
result
{:ok, result} ->
result
end
end
end
end
Now if you run this:
once = A.once(fn sleep ->
:timer.sleep(sleep)
1 + 1
end)
IO.inspect once.([1000])
IO.inspect once.([1000])
IO.inspect once.([1000])
IO.inspect once.([1000])
You'll see that the first line is printed after 1 second, but the next 3 are printed instantly, because the result is fetched from the agent.
While both already given answers are perfectly valid, the most precise translation from your javascript is shown below:
defmodule M do
use GenServer
def start_link(_opts \\ []) do
GenServer.start_link(__MODULE__, nil, name: __MODULE__)
end
def init(_args) do
Process.sleep(1_000)
{:ok, 42}
end
def value() do
start_link()
GenServer.call(__MODULE__, :value)
end
def handle_call(:value, _from, state) do
{:reply, state, state}
end
end
(1..5) |> Enum.each(&IO.inspect(M.value(), label: to_string(&1)))
Use the same metric as in #Dogbert’s answer: the first value is printed with a delay, all subsequent are printed immediately.
This is an exact analog of your memoized function using GenServer stage. GenServer.start_link/3 returns one of the following:
{:ok, #PID<0.80.0>}
{:error, {:already_started, #PID<0.80.0>}}
That said, it is not restarted if it’s already started. I do not bother to check the returned value since we are all set in any case: if it’s the initial start, we call the heavy function, if we were already started, the vaklue is already at fingers in the state.

How to pack / unpack a hex string (high nibble first) with Elixir

I was wondering how I would work with hex strings in Elixir. Specifically, I'm interested in converting from Hex to ASCII.
In Ruby, an implementation of this may be:
["001C7F616A8B002128C1A33E8100"].pack('H*').gsub(/[^[:print:]]/, '.')
How would I accomplish this task with Elixir? I have tried:
<<00, 01, C7, F6...>>
but this isn't a correct representation of the hex for a string. Thanks for your time and assistance!
So I've made some progress but am currently struggling with the recursion aspect of this.
This is my solution thus far:
defmodule ElixirNetworkTools do
def decode(payload) do
upper_payload = String.upcase payload
case Base.decode16(upper_payload) do
:error -> decode_with_nonprintable_characters(payload)
{:ok, decoded_payload} -> decoded_payload
end
|> IO.write
end
def decode_with_nonprintable_characters(payload) do
String.chunk(payload, ~r/\w{2}/)
|> Enum.each(fn(byte) ->
case Base.decode16(byte) do
:error -> '.'
{:ok, decoded_payload} -> decoded_payload
end
end)
end
end
Here is another solution to the problem. A couple things before we start:
You can pass case: :mixed to Base.decode16/2: Base.decode16(string, case: :mixed), for this reason, you don't need do upcase before.
If you are going to raise on an invalid string, don't bother checking, just call decode16 directly as it also checks the size.
This means we can start with:
decoded = Base.decode16!(string, case: :mixed)
Now you need to replace non-printable characters. Don't use String.printable?/1 because it is about UTF-8 and not ASCII. We need to implement our own function but what makes more sense: to raise or replace them? It seems it must be considered an error if someone send invalidate data? If that is the case:
def validate_ascii!(<<h, t::binary>>) when h <= 127 do
validate_ascii!(t)
end
def validate_ascii!(<<>>) do
true
end
def validate_ascii!(rest) do
raise "invalid ascii on string starting at: #{rest}"
end
Alternatively you can just remove the last clause and it fail too.
Now we can put it together:
decoded = Base.decode16!(string, case: :mixed)
validate_ascii!(decoded)
decoded
EDIT: If you need to replace non-ascii by dots:
def keep_ascii(<<h, t::binary>>, acc) when h <= 127 do
keep_ascii(t, acc <> <<h>>)
end
def keep_ascii(<<_, t::binary>>, acc) do
keep_ascii(t, acc <> ".")
end
def keep_ascii(<<>>, acc) do
acc
end
The solution ended up being as follows, though if there is a cleaner or better solution I would be very interested in knowing it.
defmodule ElixirNetworkTools do
#doc """
The decode function takes a hexadecimal payload, such as one generated
by Snort, and returns the ASCII representation of the string.
## Example
iex> ElixirNetworkTools.decode("436F6E74656E742D4C656E6774683A203132")
{:ok, "Content-Length: 12"}
"""
def decode(payload) do
case _validate_length_of_snort(payload) do
:error -> raise "Invalid length hex string. Must be even length. Exiting"
_ -> nil
end
decoded = String.upcase(payload)
|> _do_decode
|> to_string
{:ok, decoded}
end
#doc """
Internal function used to manually process the hexadecimal payload,
and builds a char list of the printable characters. If a character is
not printable, we instead use periods.
## Example
iex> ElixirNetworkTools._do_decode("436F6E74656E742D4C656E6774683A203132")
["Content-Length: 12"]
"""
def _do_decode(payload) do
Base.decode16!(payload)
|> String.chunk(:printable)
|> Enum.map(fn(chunk) ->
case String.printable? chunk do
true -> chunk
_ -> "."
end
end)
end
#doc """
Internal function used to validate the length of the hexadecimal payload.
Hexadecimal strings should have an even number of characters.
## Example
iex> ElixirNetworkTools._validate_length_of_snort("436F6E74656E742D4C656E6774683A203132")
:ok
"""
def _validate_length_of_snort(payload) do
String.length(payload)
|> rem(2)
|> case do
0 -> :ok
_ -> :error
end
end
end

Why does not init:stop() terminate directly?

My code for display all days in this year.
I don't understand why if NewSec =< EndSec -> init:stop() end did not execute the first time in run_calendar?
I expect init:stop() could be executed first time but it is not.
What is wrong?
Code:
-module(cal).
-export([main/0]).
main() ->
StartSec = calendar:datetime_to_gregorian_seconds({{2009,1,1},{0,0,0}}),
EndSec = calendar:datetime_to_gregorian_seconds({{2009,12,31},{0,0,0}}),
run_calendar(StartSec,EndSec).
run_calendar(CurSec, EndSec) ->
{Date,_Time} = calendar:gregorian_seconds_to_datetime(CurSec),
io:format("~p~n", [Date]),
NewSec = CurSec + 60*60*24,
if NewSec =< EndSec -> init:stop() end,
run_calendar(NewSec, EndSec).
Result:
wk# erlc cal.erl
wk# erl -noshell -s cal main
{2009,1,1}
{2009,1,2}
{2009,1,3}
{2009,1,4}
{2009,1,5}
...
{2009,12,22}
{2009,12,23}
{2009,12,24}
{2009,12,25}
{2009,12,26}
{2009,12,27}
{2009,12,28}
{2009,12,29}
{2009,12,30}
{2009,12,31}
wk#
I believe that init:stop() is an asynchronous process that will attempt to shut down the runtime smoothly. According to the docs, "All applications are taken down smoothly, all code is unloaded, and all ports are closed before the system terminates."
It probably takes a while to actually stop, because you have an actively running process. If you change "init:stop()" to "exit(stop)", it will terminate immediately:
3> cal:main().
{2009,1,1}
** exception exit: stop
in function cal:run_calendar/2
Init:stop is asynchronous and it will take time to quit. An alternate way would be to wrap up the test in the call itself and use pattern matching to terminate the loop:
-module(cal).
-export([main/0]).
main() ->
StartSec = calendar:datetime_to_gregorian_seconds({{2009,1,1},{0,0,0}}),
EndSec = calendar:datetime_to_gregorian_seconds({{2009,12,31},{0,0,0}}),
run_calendar(false, StartSec, EndSec).
run_calendar(true, _StartSec, _EndSec) ->
finished;
run_calendar(false, CurSec, EndSec) ->
{Date,_Time} = calendar:gregorian_seconds_to_datetime(CurSec),
io:format("~p~n", [Date]),
NewSec = CurSec + 60*60*24,
run_calendar(NewSec =< EndSec, NewSec, EndSec).
(or something similar, hopefully you get the idea)
You have a mistake in your if statement
You said
if NewSec =< EndSec -> init:stop() end,
This is incorrect. You have to write something like:
if
A =< B -> do something ...;
true -> do something else
end
The if syntax is
if
Condition1 -> Actions1;
Condition2 -> Actions2;
...
end
One of these conditions must always be true.
Why is this?
Erlang is a functional language, not a statement language. In an functional
language every expression must have a value. if is an expression, so it must have a value.
The value of (if 2 > 1 -> 3 end) is 3 but what is the value of
(if 1 > 2 -> 3 end) - answer it has no value - but it must have a value
everything must have a value.
In a statement language everything is evaluated for its side effect -so this would
be a valid construction.
In Erlang you will generate an exception.
So your code generates an exception - which you don't trap so you don't see it and
init:stop() never gets called ...

Resources