Hi Erlang beginner here trying to implement a basic ANN (artificial neural network) following this tutorial from Wil Chung. The code is exactly as in his github repo.
Running this:
1> ann_test:run().
causes a bunch (five to be precise) errors like this:
=ERROR REPORT==== 18-Feb-2015::07:11:49
=== Error in process <0.60.0> with exit value: {undef,[{ann,perceptron,[[],[],[]],[]}]}
=ERROR REPORT==== 18-Feb-2015::07:11:49
=== Error in process <0.61.0> with exit value: {undef,[{ann,perceptron,[[],[],[]],[]}]}
Somehow spawning the processes here in ann_test.erl:
X1_pid = spawn(ann, perceptron, [[],[],[]]),
causes the trouble but I'm not sure how to trace it. Tried locating the issue with redbug pointing it at ann_test:run and ann:perceptron but it doesn't show anything. Also tried adding process_flag(trap_exit, true) into run() but nothing again. Also tried adding -compile(export_all) just in case.
Could anyone point me into right direction? Many thanks.
This code is bugged. This error means that there is no exported function ann:perceptron/3 which matches arguments. There is only ann:perceptron/4. It is used properly in ann_test:setup/0 so to fix it, just add another empty list:
run() ->
ann_graph:start(),
X1_pid = spawn(ann, perceptron, [[],[],[]]),
X2_pid = spawn(ann, perceptron, [[],[],[]]),
H1_pid = spawn(ann, perceptron, [[],[],[]]),
H2_pid = spawn(ann, perceptron, [[],[],[]]),
O_pid = spawn(ann, perceptron, [[],[],[]]),
change to:
run() ->
ann_graph:start(),
X1_pid = spawn(ann, perceptron, [[],[],[],[]]),
X2_pid = spawn(ann, perceptron, [[],[],[],[]]),
H1_pid = spawn(ann, perceptron, [[],[],[],[]]),
H2_pid = spawn(ann, perceptron, [[],[],[],[]]),
O_pid = spawn(ann, perceptron, [[],[],[],[]]),
Note that this code doesn't clean after execution and there are errors after eventual re-execution in the same session. To kill registered process ann_grapher you can use exit(whereis(ann_grapher), kill).
You can read this error message {undef,[{ann,perceptron,[[],[],[]],[]}]} this way:
there is no function (undef)
in module ann
called perceptron
that takes three arguments, which all are empty lists [[], [], []]
And that is correct, because there is only one definition, which takes 4 arguments, not three. In ann_test:setup, perceptron is spawned with four empty lists. You could try that.
In other words, the tuple inside the error massege has structure {Module, Function, ListOfArguments, NotSureWhatThatIs}
Related
Akka - Discriminated Unions as messages in F#
I am unable to use discriminated unions as messages to akka actors. If anyone can point me at an example that does this, it would be much appreciated.
My own attempt at this is at git#github.com:Tweega/AkkaMessageIssue.git. (snippets below). It is a cutdown version of a sample found at https://github.com/rikace/AkkaActorModel.git (Chat project)
Problem
The DU message never finds its target on the server actor, but is sent to the deadletter box. If I send Objects, instead, they do arrive.
If I send a DU, but set my server actor to listen for generic Objects, the message does arrive, but its type is
seq [seq [seq []]
and I can't get at underlying DU.
The DU I am trying to send as message
type PrinterJob =
| PrintThis of string
| Teardown
The client code
let system = System.create "MyClient" config
let chatClientActor =
spawn system "ChatClient" <| fun mailbox ->
let server = mailbox.Context.ActorSelection("akka.tcp://MyServer#localhost:8081/user/ChatServer")
let rec loop nick = actor {
let! (msg:PrinterJob) = mailbox.Receive()
server.Tell(msg)
return! loop nick
}
loop ""
while true do
let input = Console.ReadLine()
chatClientActor.Tell(PrintThis(input))
Messages are forwarded to the client from console input
while true do
let input = Console.ReadLine()
chatClientActor.Tell(PrintThis(input))
The server code
let system = System.create "MyServer" config
let chatServerActor =
spawn system "ChatServer" <| fun (mailbox:Actor<_>) ->
let rec loop (clients:Akka.Actor.IActorRef list) = actor {
let! (msg:PrinterJob) = mailbox.Receive()
printfn "Received %A" msg //Received seq [seq [seq []]; seq [seq [seq []]]] ???
match msg with
| PrintThis str ->
Console.WriteLine("Printing: {0} Do we get this?", str)
return! loop clients
| Teardown ->
Console.WriteLine("Tearing down now")
return! loop clients
}
loop []
Dependencies
(I am not using paket here) - PM commands below:
Install-Package Akka -Version 1.4.23
Install-Package Akka.Remote -Version 1.4.23
Install-Package Akka.FSharp -Version 1.4.23
I am hosting the application in net5.0
Constructor argument names - oddity?
When passing in class instances as objects, akka seems to be sensitive to the name of constructor parameters. The message gets handled, but the data is not copied across from client to server. If you have a property called Username, the constructor parameter cannot be, for example, uName, otherwise its value is null when it reaches the server. Code for this is in branch params.
type DoesWork(montelimar: string) =
member x.Montelimar = montelimar
type DoesNotWork(montelimaro: string) =
member x.Montelimar = montelimaro
I opened an issue in the Akka.NET repository: https://github.com/akkadotnet/akka.net/issues/5194
And added a detailed reproduction for this: https://github.com/akkadotnet/akka.net/pull/5196
But it looks like Newtonsoft.Json really can't perform this deserialization without being given a type hint, which Akka.NET's network serialization does not do by default for JSON:
type TestUnion =
| A of string
| B of int * string
type TestUnion2 =
| C of string * TestUnion
| D of int
[<Fact(Skip="JSON.NET really does not support even basic DU serialization")>]
member _.``JSON.NET must serialize DUs`` () =
let du = C("a-11", B(11, "a-12"))
let settings = new JsonSerializerSettings()
settings.Converters.Add(new DiscriminatedUnionConverter())
let serialized = JsonConvert.SerializeObject(du, settings)
let deserialized = JsonConvert.DeserializeObject(serialized, settings)
Assert.Equal(du :> obj, deserialized)
That test will not pass and it doesn't use any of Akka.NET's infrastructure at all - so the default JSON serializer simply won't work for real-world F# use cases.
We can try changing the defaults of our serialization system to include a type hint, but that will take a lot of validation testing (for old Akka.Persistence data serialized without one).
A better solution, which my pull request validates, is to use Hyperion for polymorphic serialization instead - it will be similarly transparent to you but it has much more robust handling for complex types than Newtonsoft.Json and is actually faster: https://getakka.net/articles/networking/serialization.html#how-to-setup-hyperion-as-default-serializer
I'm toying around with Elm processes in order to learn more about how they work. In parts of this, I'm trying to implement a timer.
I bumped into an obstacle, however: I can't find a way to access the result of a process' task in the rest of the code.
For a second, I hoped that if I make the task resolve with a Cmd, the Elm runtime would be kind enough to perform that effect for me, but that was a naive idea:
type Msg
= Spawned Process.Id
| TimeIsUp
init _ =
( Nothing
, Task.perform Spawned (Process.spawn backgroundTask)
)
backgroundTask : Task.Task y (Platform.Cmd.Cmd Msg)
backgroundTask =
Process.sleep 1000
-- pathetic attempt to send a Msg starts here
|> Task.map ( always
<| Task.perform (always TimeIsUp)
<| Task.succeed ()
)
-- and ends here
|> Task.map (Debug.log "Timer finished") -- logs "Timer finished: <internals>"
update msg state =
case msg of
Spawned id ->
(Just id, Cmd.none)
TimeIsUp ->
(Nothing, Cmd.none)
view state =
case state of
Just id ->
text "Running"
Nothing ->
text "Time is up"
The docs say
there is no public API for processes to communicate with each other.
I'm not sure if that implies that a process can't cummunicate with the rest of the app.
Is there any way to have update function receive a TimeIsUp once the process exits?
There is one way but it requires a port of hell:
make a fake HTTP request from the process,
then intercept it via JavaScript
and pass it back to Elm.
port ofHell : (() -> msg) -> Sub msg
subscriptions _ =
ofHell (always TimeIsUp)
backgroundTask : Task.Task y (Http.Response String)
backgroundTask =
Process.sleep 1000
-- nasty hack starts here
|> Task.andThen ( always
<| Http.task { method = "EVIL"
, headers = []
, url = ""
, body = Http.emptyBody
, resolver = Http.stringResolver (always Ok "")
, timeout = Nothing
}
)
Under the hood, Http.task invokes new XMLHttpRequest(), so we can intercept it by redefining that constructor.
<script src="elm-app.js"></script>
<div id=hack></div>
<script>
var app = Elm.Hack.init({
node: document.getElementById('hack')
})
var orig = window.XMLHttpRequest
window.XMLHttpRequest = function () {
var req = new orig()
var orig = req.open
req.open = function (method) {
if (method == 'EVIL') {
app.ports.ofHell.send(null)
}
return orig.open.apply(this, arguments)
}
return req
}
</script>
The solution is not production ready, but it does let you continue playing around with Elm processes.
Elm Processes aren't a fully fledged API at the moment. It's not possible to do what you want with the Process library on its own.
See the notes in the docs for Process.spawn:
Note: This creates a relatively restricted kind of Process because it cannot receive any messages. More flexibility for user-defined processes will come in a later release!
and the whole Future Plans section, eg.:
Right now, this library is pretty sparse. For example, there is no public API for processes to communicate with each other.
There is a program of three modules. The Print module receives a number from the keyboard, passes it to another module, receives the response, and displays it on the screen. The Proc1 and Proc2 modules receive a number, perform calculations, and send the result back.
defmodule Launch do
#moduledoc """
Documentation for `Launch`.
"""
#doc """
"""
def start() do
children = [
%{
id: Print,
start: {Print, :print, []}
},
%{
id: Proc1,
start: {Proc1, :proc1, []}
},
%{
id: Proc2,
start: {Proc2, :proc2, []}
}
]
Supervisor.start_link(children, strategy: :one_for_one)
end
end
defmodule Print do
def print() do
num =
IO.gets("Input number: ")
|> String.trim()
|> String.to_integer()
if num >= 0 do
send(Proc1, {self(), num})
else
send(Proc2, {self(), num})
end
receive do
num -> IO.puts(num)
after
500 ->
print()
end
print()
end
end
defmodule Proc1 do
def proc1() do
receive do
{pid, num} ->
send(pid, 100/num)
proc1()
_e ->
IO.puts("Error")
end
end
end
defmodule Proc2 do
def proc2() do
receive do
{pid, num} ->
send(pid, 1000/num)
proc2()
_e ->
IO.puts("Error")
end
end
end
I am trying to run all processes under the supervision of a single Supervisor. But there is a problem-only the first "child" is started, the other "children" are not started. In the example above, the Print process will start, but Proc1 and Proc2 will not start. How do I run all processes under one Supervisor? Important note: the Print process must get the addresses of the Proc1 and Proc2 processes for communication.
There are many issues with the code you’ve posted.
Registered processes
To be able to use process name as Process.dest() in a call to Kernel.send/2, one should start the named process.
Supervisor.start_link/2
Supervisor.start_link/2 expects a list of tuples, with modules and functions that immediately return, having the process started as a side effect. These functions are called, and there would not be any magic: if this is an infinitely recursive function, the execution flow would be deadlocked inside, waiting for the message in receive/1.
Supervisor performs some magic by automatically monitoring and restarting children for you, but it does nothing to spawn the separate processes. GenServer encapsulates this functionality and provides a handy way to not bother about spawning processes.
Solution
What you might do, is to spawn all three processes, manually monitor them, and react on {:DOWN, ref, :process, pid, reason} message respawning the died process. This is exactly what Supervisor effectively does under the hood for children.
Launch
defmodule Launch do
def start() do
proc1 = spawn(&Proc1.proc1/0)
proc2 = spawn(&Proc2.proc2/0)
print = spawn(fn -> Print.print(proc1, proc2) end)
Process.monitor(proc1)
Process.monitor(proc2)
Process.monitor(print)
receive do
msg -> IO.inspect(msg)
end
end
end
Print
defmodule Print do
def print(pid1, pid2) do
num =
IO.gets("Input number: ")
|> String.trim()
|> String.to_integer()
if num >= 0 do
send(pid1, {self(), num})
else
send(pid2, {self(), num})
end
receive do
num -> IO.puts(num)
end
print(pid1, pid2)
end
end
The other two modules are fine.
Here is how it will look like in iex
iex|1 ▶ c "/tmp/test.ex"
#⇒ [Launch, Print, Proc1, Proc2]
iex|2 ▶ Launch.start
Input number: 10
10.0
Input number: 1000
0.1
Input number: a
#⇒ {:DOWN, #Reference<0.3632020665.3980394506.95298>,
# :process, #PID<0.137.0>,
# {:badarg,
# [
# {:erlang, :binary_to_integer, ["a"], []},
# {Print, :print, 2, [file: '/tmp/test.ex', line: 22]}
# ]}}
Now instead of printing this out, respawn the failed process, and you will get a bare implementation of the supervised intercommunicating processes. For all_for_one strategy that could be achieved with:
receive do
{:DOWN, _, _, _, _} ->
Process.exit(print, :normal)
Process.exit(proc1, :normal)
Process.exit(proc2, :normal)
start()
end
How can I call function func() in a module called App.Reporting.Name
based on the string "name" which is not known until runtime
using String.to_atom or to_existing_atom does not work :
alias App.Reporting.Name
module = "name" |> String.capitalise |> String.to_atom
apply(module, :func, [])
Without the alias, this does not work either
module = "App.Reporting.Name" |> String.to_atom
apply(module, :func, [])
I get an (UndefinedFunctionError) and (module :"App.Reporting.Name" is not available)
thanks
Your second approach is almost correct, you just need to prefix Elixir. because App.Reporting.Name is equal to :"Elixir.App.Reporting.Name", not :"App.Reporting.Name" since Elixir prefixes all module names (names starting with an uppercase letter) with Elixir. before turning it into an atom:
iex(1)> App.Reporting.Name == :"App.Reporting.Name"
false
iex(2)> App.Reporting.Name == :"Elixir.App.Reporting.Name"
true
So, this code should work:
module = "Elixir.App.Reporting.Name" |> String.to_atom
apply(module, :func, [])
and so should this:
module = Module.concat(App.Reporting, "name" |> String.capitalize |> String.to_atom)
apply(module, :func, [])
The reason yours isn't working is because the String.to_atom does just that, turns a string into an atom. Because there is no module called "App.Reporting.Name" it's most likely App.Reporting.Name it errors.
Not sure if this is the best way to do this, just one that sprang to mind. But you could do something like this:
iex(2)> module = "Casing"
"Casing"
iex(3)> Module.concat(String, "#{module}") |> apply(:upcase, ["test sentence"])
"TEST SENTENCE"
Another solution could be to create a macro that automatically does this process, however that is not something I am that great at so you will have to go through the docs here for that one.
I'm trying to use rabbitmq-erlang-client, and confused about errors throwed by program.
I fllowed system_SUITE:queue_unbind/1 But errors are throwed when setting Exchange and Queue :
%% code
amqp_channel:call(Channel, #'exchange.declare'{exchange = X}),
amqp_channel:call(Channel, #'queue.declare'{queue = Q}),
%% it throw me same errors again and again:
** Last message in was setup_exchange_queue
** When Server state == {state,
{amqp_params_network,<<"username">>,<<"password">>,
<<"/">>,"192.168.1.173",5672,0,0,10,infinity,
none,
[#Fun<amqp_auth_mechanisms.plain.3>,
#Fun<amqp_auth_mechanisms.amqplain.3>],
[],[]},
<0.74.0>,<0.83.0>,<<"amq.direct">>,<<"queue">>,
<<"my_queue">>,undefined,undefined}
** Reason for termination ==
** {{noproc,{gen_server,call,[<0.83.0>,{close,200,<<"Goodbye">>},infinity]}},
[{gen_server,call,3,[{file,"gen_server.erl"},{line,212}]},
{mrbq,terminate,2,[{file,"src/mrbq.erl"},{line,244}]},
{gen_server,try_terminate,3,[{file,"gen_server.erl"},{line,643}]},
{gen_server,terminate,7,[{file,"gen_server.erl"},{line,809}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,240}]}]}
** exception exit: {noproc,
{gen_server,call,
[<0.83.0>,{close,200,<<"Goodbye">>},infinity]}}
code review amqp_channel.erl
%% call
call/2 -> gen_server:call/2
handle_call/3 -> handle_method_to_server/6
goto line 573, then line 888 ,and {noreply, State} returned for call as a result!!
What's wrong with above steps?
What should do to make it OK?
I have had tried cast/2,and no errors occur. But this is not what I need.