<?xml version="1.0" encoding="utf-8"?><rss version="2.0"
    xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:wfw="http://wellformedweb.org/CommentAPI/"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:atom="http://www.w3.org/2005/Atom"
    xmlns:media="http://search.yahoo.com/mrss/"
    xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
    xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
>
<channel>
  <title>Srijan Choudhary, all posts tagged: erlang</title>
  <link>https://srijan.ch/feed/all/tag:erlang</link>
  <lastBuildDate>Wed, 11 Jun 2025 02:35:00 +0000</lastBuildDate>
  <image>
    <url>https://srijan.ch/assets/favicon/favicon-32x32.png</url>
    <title>Srijan Choudhary, all posts tagged: erlang</title>
    <link>https://srijan.ch/feed/all/tag:erlang</link>
  </image>
  <sy:updatePeriod>daily</sy:updatePeriod>
  <sy:updateFrequency>1</sy:updateFrequency>
  <generator>Kirby</generator>
  <atom:link href="https://srijan.ch/feed/all.xml/tag:erlang" rel="self" type="application/rss+xml" />
  <description>Srijan Choudhary&#039;s Articles and Notes Feed for tag: erlang</description>
  <item>
    <title>2025-06-11-001</title>
    <description><![CDATA[Quick note for me to generate #Emacs TAGS file for an #Erlang project: find {src,apps,_build/default,$(dirname $(which erl))/../lib} -name "*.[he]rl" | xargs realpath --relative-to="$(pwd)" | etags.emacs -o TAGS - The relative path ensures that this works over tramp as well.]]></description>
    <link>https://srijan.ch/notes/2025-06-11-001</link>
    <guid isPermaLink="false">tag:srijan.ch:/notes/2025-06-11-001</guid>
    <category><![CDATA[erlang]]></category>
    <category><![CDATA[emacs]]></category>
    <dc:creator>Srijan Choudhary</dc:creator>
    <pubDate>Wed, 11 Jun 2025 02:35:00 +0000</pubDate>
    <content:encoded><![CDATA[<p>Quick note for me to generate <a href="/tags/emacs" class="p-category">#Emacs</a> TAGS file for an <a href="/tags/erlang" class="p-category">#Erlang</a> project:</p>
<pre><code>find {src,apps,_build/default,$(dirname $(which erl))/../lib} -name "*.[he]rl" | xargs realpath --relative-to="$(pwd)" | etags.emacs -o TAGS -</code></pre>
<p>The relative path ensures that this works over tramp as well.</p>]]></content:encoded>
    <comments>https://srijan.ch/notes/2025-06-11-001#comments</comments>
    <slash:comments>4</slash:comments>
  </item><item>
    <title>Erlang: Dialyzer HTML Reports using rebar3</title>
    <description><![CDATA[How I made a custom rebar3 plugin to generate HTML reports for dialyzer warnings]]></description>
    <link>https://srijan.ch/erlang-dialyzer-html-reports-rebar3</link>
    <guid isPermaLink="false">6072d47bb1237c000188be89</guid>
    <category><![CDATA[erlang]]></category>
    <category><![CDATA[development]]></category>
    <dc:creator>Srijan Choudhary</dc:creator>
    <pubDate>Sun, 25 Apr 2021 17:10:00 +0000</pubDate>
    <media:content url="https://srijan.ch/media/pages/blog/erlang-dialyzer-html-reports-rebar3/b5893af741-1699621096/dialyzer-html-report.png" medium="image" />
    <content:encoded><![CDATA[<h2>Introduction</h2>
<p><a href="https://erlang.org/doc/man/dialyzer.html" rel="noreferrer">Dialyzer</a> is a static analysis tool for <a href="https://www.erlang.org/" rel="noreferrer">Erlang</a>
 that identifies software discrepancies, such as definite type errors, 
code that has become dead or unreachable because of programming errors, 
and unnecessary tests, in single Erlang modules or entire (sets of) 
applications.</p> <p>Dialyzer is integrated with <a href="https://github.com/erlang/rebar3" rel="noreferrer">rebar3</a> (a build tool for Erlang), and its default output looks like this:</p><figure data-ratio="auto">
    <img src="https://srijan.ch/media/pages/blog/erlang-dialyzer-html-reports-rebar3/fcdab50184-1699621096/dialyzer-rebar3-default.png" alt="Rebar3 Dialyzer Default Output">
  
    <figcaption class="text-center">
    <code>rebar3 dialyzer</code> output  </figcaption>
  </figure>
<p>This is a good starting point, but it's not very useful in some cases:</p><ol><li>If you have lots of warnings, this output covers several screens, and it becomes difficult to parse through everything.</li><li>If you run this in some sort of continuous integration (like Jenkins), then the console output is not very friendly.</li></ol><p>One way to improve this is to generate an HTML report which can be published/emailed/opened in the browser.</p> <p>So,
 I build a rebar3 plugin that generates a nicely formatted color HTML 
report from the dialyzer output. The plugin can be found <a href="https://hex.pm/packages/rebar3_dialyzer_html" rel="noreferrer">on hex.pm</a>, or <a href="https://github.com/srijan/rebar3_dialyzer_html" rel="noreferrer">on github</a>.</p><h2>Usage</h2>
<p>Make sure you're using rebar3 version <code>3.15</code> or later.</p><ol><li>Add the plugin to your <code>rebar.config</code>:</li></ol><figure>
  <pre><code class="language-erlang">{plugins, [
    %% from hex
    {rebar3_dialyzer_html, &quot;0.2.0&quot;}
    
    %% or, latest from git
    {rebar3_dialyzer_html, {git, &quot;https://github.com/srijan/rebar3_dialyzer_html.git&quot;, {branch, &quot;main&quot;}}}
]}.</code></pre>
    <figcaption class="text-center">rebar.config snippet</figcaption>
  </figure>
<p>2. Select raw format for the dialyzer warnings file generated by rebar3 (this is a new flag available from rebar <code>3.15</code>):</p><figure>
  <pre><code class="language-erlang">{dialyzer, [
    {output_format, raw}
]}.</code></pre>
    <figcaption class="text-center">rebar.config snippet</figcaption>
  </figure>
<p>3. Run the <code>dialyzer_html</code> rebar3 command:</p><figure>
  <pre><code class="language-shellsession">$ rebar3 dialyzer_html          
===&gt; Generating Dialyzer HTML Report
===&gt; HTML Report written to _build/default/dialyzer_report.html</code></pre>
  </figure>
<p>Here's how the report looks:</p><figure data-ratio="auto">
    <img src="https://srijan.ch/media/pages/blog/erlang-dialyzer-html-reports-rebar3/b5893af741-1699621096/dialyzer-html-report.png" alt="Dialyzer HTML Report Sample">
  
    <figcaption class="text-center">
    Sample HTML report for dialyzer  </figcaption>
  </figure>
<h2>How I built the plugin</h2>
<h3>rebar3 dialyzer</h3>
<p>The rebar3 built-in dialyzer plugin does the following:</p><ol><li>Runs dialyzer with the options configured in <code>rebar.config</code></li><li>Converts the output to ANSI color format and write it to console (it has a custom function for this formatting)</li><li>Converts the output to basic format (using built-in <code>dialyzer:format/2</code>) and write it to a dialyzer_warnings file.</li></ol><p>I wanted to find out the easiest way to get a nicely formatted HTML report, ideally without forking the rebar3 project itself.</p> <p>The
 first thing I needed was a way to save the raw (machine parse-able) 
dialyzer output to the warnings file instead of the default formatted 
output. For this, I <a href="https://github.com/erlang/rebar3/issues/2524" rel="noreferrer">submitted a new feature</a> to the rebar3 project, and it introduces a new config to enable this. So, this plugin needs rebar3 version <code>3.15</code> or later.</p><h3>Plugin vs Escript</h3>
<p>Next, to actually parse and output the HTML file, I would need to run some Erlang code. There are two options I considered:</p><ol><li><u>Escript called from Makefile/wrapper</u><br>This option works okay, but we cannot re-use any rebar3 internal function or State. I wanted to use rebar3's own custom function for formatting the dialyzer warnings, so decided to not go with this option.<br></li><li><u>Custom rebar3 plugin</u><br>Doing it this way makes it easy for anyone to use, and I can re-use things already implemented in rebar3 itself. So, I decided to use this option.<br></li></ol><h3>HTML output</h3>
<p>Now, in the custom rebar3 plugin, I needed to convert the ANSI color-coded output given by <code>rebar_dialyzer_format:format_warnings/2</code> into something for HTML.</p> <p>I thought of the following options:</p><ol><li>rebar3 uses the <a href="https://github.com/project-fifo/cf" rel="noreferrer">cf library</a> to convert tagged strings to ANSI color codes. I can use something like dependency injection to replace the <code>cf</code> module with my own module so that the tagged strings are directly converted to HTML without even going to the intermediate ANSI color-coded format.<br><br>This method seemed very hacky, so I decided not to pursue it. But, if rebar3 makes the dialyzer format interface configurable, I can reevaluate this approach.<br></li><li>Convert by writing a library in Erlang for ANSI code to HTML tags conversion.<br>There is a library called <a href="https://github.com/stephlow/ansi_to_html" rel="noreferrer">ansi_to_html</a> in elixir - but didn't want to add a huge dependency like that.<br>But writing a new Erlang library to do this can be a future optimization.<br></li><li>Convert using a JS library after page load. I found a javascript library called <a href="https://github.com/drudru/ansi_up" rel="noreferrer">ansi_up</a> which can convert ANSI codes to HTML color tags, or it can add CSS classes that can be styled as required.<br></li></ol><p>I
 opted for approach #3 because it was the easiest. I also grouped the 
warnings by app name so that all warnings for a single app are in one 
place, and the report includes the number of warnings per app.</p> <p>Also,
 if the JS library could not be loaded (for example due to no internet, 
or any security headers), then it will still show the basic formatted 
output using <code>dialyzer:format/2</code>.</p><h2>Future Improvements</h2>
<ol><li>I
 want to remove the dependency on Javascript, and want to write/use a 
pure Erlang library that can convert the ANSI codes to HTML.</li><li>Ideally,
 rebar3 itself can separate the dialyzer warning parsing and formatting 
into different functions, and make it possible to override the 
formatting function so that any plugin can pass its own formatting 
function into the dialyzer plugin.</li><li>This can even run <code>git</code>
 commands in the shell to figure out if any lines changed in the most 
recent commit involve a warning, and maybe highlight them especially in 
the report. This can be useful CI reports on pull requests.</li><li>Maybe make the format plug-able so the report can be saved in any JSON / XML or any custom format.</li></ol><hr />
<p>Let me know in the comments below, or on <a href="https://twitter.com/srijan4" rel="noreferrer">twitter</a>/<a href="https://github.com/srijan/rebar3_dialyzer_html" rel="noreferrer">github </a>if you have any suggestions for this plugin.</p>]]></content:encoded>
    <comments>https://srijan.ch/erlang-dialyzer-html-reports-rebar3#comments</comments>
    <slash:comments>0</slash:comments>
  </item><item>
    <title>Erlang: find cross-app calls using xref</title>
    <description><![CDATA[Using xref magic to query compiled beam files and find cross-application function calls in Erlang]]></description>
    <link>https://srijan.ch/erlang-find-cross-app-calls-using-xref</link>
    <guid isPermaLink="false">606006e8b1237c000188badf</guid>
    <category><![CDATA[erlang]]></category>
    <category><![CDATA[development]]></category>
    <dc:creator>Srijan Choudhary</dc:creator>
    <pubDate>Sun, 28 Mar 2021 09:05:00 +0000</pubDate>
    <media:content url="https://srijan.ch/media/pages/blog/erlang-find-cross-app-calls-using-xref/5390618c89-1699621096/omar-flores-moo6k3raiwe-unsplash.jpg" medium="image" />
    <content:encoded><![CDATA[<figure data-ratio="auto">
    <img src="https://srijan.ch/media/pages/blog/erlang-find-cross-app-calls-using-xref/5390618c89-1699621096/omar-flores-moo6k3raiwe-unsplash.jpg" alt="Erlang: find cross-app calls using xref">
  
  </figure>
<p>At work, we use the <a href="https://adoptingerlang.org/docs/development/umbrella_projects/" rel="noreferrer">multi-app project pattern</a> to organize our codebase. This lets us track everything in a single repository but still keep things isolated.</p> <p>For isolation, we wanted to restrict apps to only be able to call the public interfaces of other apps (similar to <a href="https://en.wikipedia.org/wiki/Facade_pattern" rel="noreferrer">facade pattern</a>).
 However, since everything in Erlang is in a global namespace, nothing 
prevents code in one app to call the (exported) functions from another 
app.</p> <p>Next best solution—detect the above scenario and raise warnings during code review/CI.</p> <p><a href="https://erlang.org/doc/apps/tools/xref_chapter.html" rel="noreferrer">Xref</a> to the rescue:</p><blockquote>
  Xref is a cross reference tool that can be used for finding dependencies between functions, modules, applications and releases.  </blockquote>
<p>Xref
 includes some predefined analysis patterns that perform some common 
tasks like searching for undefined functions, deprecated function calls,
 unused exported functions, etc.</p> <p>How it works: when <a href="https://erlang.org/doc/man/xref.html#xref_server" rel="noreferrer">xref server</a> is started and some modules/applications/releases are added for analysis, it builds a <strong>Call Graph</strong>: a directed graph data structure containing the calls between functions, modules, applications or releases. It also creates an <strong>Inter Call Graph</strong> which holds information about indirect calls (chain of calls). It exposes a very powerful <a href="https://erlang.org/doc/man/xref.html#query" rel="noreferrer">query language</a>, which can be used to extract any information we want from the above graph data structures.</p> <p>To demonstrate this, I created a sample multi-app repository: <a href="https://github.com/srijan/library_sample" rel="noreferrer">library_sample</a>. There are some cross-app function calls in this code that we want to detect.</p> <p>This repo is supposed to represent the functionality of a physical Library. It has four apps: <code>library</code>, <code>library_api</code>, <code>library_catalog</code>, and <code>library_inventory</code>. <code>library_catalog</code> has metadata about the books in the library, <code>library_inventory</code> has information about the availability of books, return dates, etc., <code>library_api</code> has HTTP handlers which call the above, and <code>library</code> is the main app which brings it all together.</p> <p>Let’s say we want that <code>library_api</code> can call <code>library_catalog</code> and <code>library_inventory</code> functions, but catalog and inventory cannot call each other directly.</p> <p>First, we clone the repo and run rebar3 shell:</p><figure>
  <pre><code class="language-shellsession">$ git clone https://github.com/srijan/library_sample
Cloning into &#039;library_sample&#039;...
remote: Enumerating objects: 29, done.
remote: Counting objects: 100% (29/29), done.
remote: Compressing objects: 100% (19/19), done.
remote: Total 29 (delta 3), reused 29 (delta 3), pack-reused 0
Unpacking objects: 100% (29/29), 910.62 KiB | 2.53 MiB/s, done.

$ cd library_sample

$ ./rebar3 shell
===&gt; Verifying dependencies...
===&gt; Analyzing applications...
===&gt; Compiling library_inventory
===&gt; Compiling library_catalog
===&gt; Compiling library
===&gt; Compiling library_api
Erlang/OTP 23 [erts-11.1.7] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]

Eshell V11.1.7  (abort with ^G)
1&gt;</code></pre>
  </figure>
<p>Then, we start xref and add our build directory for analysis:</p><figure>
  <pre><code class="language-erlang">1&gt; xref:start(s).
{ok,&lt;0.185.0&gt;}

2&gt; xref:add_directory(s, &quot;_build/default/lib&quot;, [{recurse, true}]).
{ok,[library_api,library_app,library_catalog,
     library_inventory,library_sample_app,library_sample_sup,
     library_sup]}</code></pre>
  </figure>
<p>Using <code>xref:q/2</code> for querying the constructed call graph:</p><figure>
  <pre><code class="language-erlang">3&gt; xref:q(s, &quot;E | library_inventory || library_catalog&quot;).
{ok,[]}

4&gt; xref:q(s, &quot;E | library_catalog || library_inventory&quot;).
{ok,[{{library_catalog,get_by_id,1},
      {library_inventory,get_available_copies,1}}]}</code></pre>
  </figure>
<p>This means that there are no direct calls from the <code>library_inventory</code> application to the <code>library_catalog</code> application. But, there is a direct call from <code>library_catalog:get_by_id/1</code> to <code>library_inventory:get_available_copies/1</code>.</p> <p>The query <code>E | library_catalog || library_inventory</code> can be read as:</p><ul><li><code>E</code> = All Call Graph Edges</li><li><code>|</code> = The subset of calls <strong>from</strong> any of the vertices. So <code>| library_catalog</code> creates a subset which contains calls from the <code>library_catalog</code> app.</li><li><code>||</code> = The subset of calls <strong>to</strong> any of the vertices. So, <code>|| library_inventory</code> further creates a subset of the previous subset which contains calls to the <code>library_inventory</code> app.</li></ul><p>To get both direct and indirect calls, <code>closure E</code> has to be used:</p><figure>
  <pre><code class="language-erlang">5&gt; xref:q(s, &quot;closure E | library_catalog || library_inventory&quot;).
{ok,[{{library_catalog,get_by_id,1},
      {library_inventory,get_all,0}},
     {{library_catalog,get_by_id,1},
      {library_inventory,get_available_copies,1}}]}</code></pre>
  </figure>
<p>This tells us that there is an indirect direct call from  <code>library_catalog:get_by_id/1</code> to <code>library_inventory:get_all/0</code>.</p> <p>The query language is very powerful, and there are more interesting examples in the <a href="https://erlang.org/doc/apps/tools/xref_chapter.html#expressions" rel="noreferrer">xref user’s guide</a>.</p> <p>But
 this only runs the required queries manually in Erlang shell. We want 
to be able to run it in continuous integration. Luckily, rebar3 comes 
with a way to <a href="https://rebar3.readme.io/docs/configuration#xref" rel="noreferrer">specify custom xref queries</a> to run when running <code>./rebar3 xref</code>, and to raise an error if they don’t match against the expected value defined.</p> <p>Here’s the xref section from my <code>rebar.config</code>:</p><figure>
  <pre><code class="language-erlang">{xref_queries, [
                {&quot;closure E | library_catalog || library_inventory&quot;, []},
                {&quot;closure E | library_inventory || library_catalog&quot;, []}
               ]}.</code></pre>
    <figcaption class="text-center">rebar.config</figcaption>
  </figure>
<p>This performs the two queries I want and matches them against the the target value of <code>[]</code>. Sample output:</p><figure>
  <pre><code class="language-shellsession">$ ./rebar3 xref
===&gt; Verifying dependencies...
===&gt; Analyzing applications...
===&gt; Compiling library_inventory
===&gt; Compiling library_catalog
===&gt; Compiling library
===&gt; Compiling library_api
===&gt; Running cross reference analysis...
===&gt; Query closure E | library_catalog || library_inventory
 answer []
 did not match [{{library_catalog,get_by_id,1},{library_inventory,get_all,0}},
                {{library_catalog,get_by_id,1},
                 {library_inventory,get_available_copies,1}}]</code></pre>
  </figure>
<p>So, now this is ready for automation.</p>]]></content:encoded>
    <comments>https://srijan.ch/erlang-find-cross-app-calls-using-xref#comments</comments>
    <slash:comments>1</slash:comments>
  </item><item>
    <title>Clean boot in erlang relx release</title>
    <description><![CDATA[Booting Erlang release in clean or safe mode]]></description>
    <link>https://srijan.ch/clean-boot-in-erlang-relx-release</link>
    <guid isPermaLink="false">6030d3dab5e0920001f557ca</guid>
    <category><![CDATA[erlang]]></category>
    <category><![CDATA[development]]></category>
    <dc:creator>Srijan Choudhary</dc:creator>
    <pubDate>Fri, 15 Apr 2016 04:50:00 +0000</pubDate>
    <content:encoded><![CDATA[<p>We use relx to release out erlang applications, and faced a problem:</p> <p>Our application was crashing at bootup, and therefore we were not 
able to even open a remote shell on which we can run any correction 
functions.</p> <p>One way to solve this (which we've been using till now) is to also 
install erlang on the machine which has the release, and open an erlang 
shell with the correct library path set.</p> <p>But, the release generated by relx provides another mechanism which does not need erlang installed.</p> <p>The solution is: erlang boot scripts.</p> <p>Detailed information about boot scripts can be found at: <a href="http://erlang.org/doc/system_principles/system_principles.html#id59026">http://erlang.org/doc/system_principles/system_principles.html#id59026</a></p> <p>relx ships a <code>start_clean.boot</code> boot script with the release, which loads the code for and starts the applications kernel and stdlib.</p> <p>Sample command:</p><figure>
  <pre><code class="language-shellsession">${RELEASE_DIR}/myapplication/bin/myapplication console_boot start_clean</code></pre>
  </figure>
]]></content:encoded>
    <comments>https://srijan.ch/clean-boot-in-erlang-relx-release#comments</comments>
    <slash:comments>0</slash:comments>
  </item><item>
    <title>Basic Implementation of A* in Erlang</title>
    <description><![CDATA[Implementing the path finding algorithm A* in Erlang]]></description>
    <link>https://srijan.ch/basic-implementation-of-a-in-erlang</link>
    <guid isPermaLink="false">6030d3dab5e0920001f557c8</guid>
    <category><![CDATA[erlang]]></category>
    <category><![CDATA[development]]></category>
    <dc:creator>Srijan Choudhary</dc:creator>
    <pubDate>Sat, 03 Aug 2013 00:00:00 +0000</pubDate>
    <content:encoded><![CDATA[<p>Recently I had to write some path finding algorithms in Erlang. The 
first version I chose was A*. But, there is no easy way to implent A* in
 a distributed way. So, this is the simplest implementation possible. I 
may rewrite it later if I find a better way.</p> <p>This code is mostly a modified version of <a href="http://stevegilham.blogspot.in/2008/10/first-refactoring-of-star-in-erlang.html">this one</a>.</p> <p>The code <a href="https://gist.github.com/srijan/6142366#file-astar-erl">hosted on gist</a> follows below, followed by some notes.</p><figure>
  <pre><code class="language-erlang">-module(astar).

-type cnode() :: {integer(), integer()}.

-define(MINX, 0).
-define(MINY, 0).
-define(MAXX, 10).
-define(MAXY, 10).

-export([
         astar/2,
         neighbour_nodes/2
        ]).

%% @doc Performs A* for finding a path from `Start&#039; node to `Goal&#039; node
-spec astar(cnode(), cnode()) -&gt; list(cnode()) | failure.
astar(Start, Goal) -&gt;
    ClosedSet = sets:new(),
    OpenSet   = sets:add_element(Start, sets:new()),

    Fscore    = dict:store(Start, h_score(Start, Goal), dict:new()),
    Gscore    = dict:store(Start, 0, dict:new()),

    CameFrom  = dict:store(Start, none, dict:new()),

    astar_step(Goal, ClosedSet, OpenSet, Fscore, Gscore, CameFrom).

%% @doc Performs a step of A*.
%% Takes the best element from `OpenSet&#039;, evaluates neighbours, updates scores, etc..
-spec astar_step(cnode(), set(), set(), dict(), dict(), dict()) -&gt; list(cnode()) | failure.
astar_step(Goal, ClosedSet, OpenSet, Fscore, Gscore, CameFrom) -&gt;
    case sets:size(OpenSet) of
        0 -&gt;
            failure;
        _ -&gt;
            BestStep = best_step(sets:to_list(OpenSet), Fscore, none, infinity),
            if
                Goal == BestStep -&gt;
                    lists:reverse(reconstruct_path(CameFrom, BestStep));
                true -&gt;
                    Parent     = dict:fetch(BestStep, CameFrom),
                    NextOpen   = sets:del_element(BestStep, OpenSet),
                    NextClosed = sets:add_element(BestStep, ClosedSet),
                    Neighbours = neighbour_nodes(BestStep, Parent),

                    {NewOpen, NewF, NewG, NewFrom} = scan(Goal, BestStep, Neighbours, NextOpen, NextClosed, Fscore, Gscore, CameFrom),
                    astar_step(Goal, NextClosed, NewOpen, NewF, NewG, NewFrom)
            end
    end.

%% @doc Returns the heuristic score from `Current&#039; node to `Goal&#039; node
-spec h_score(Current :: cnode(), Goal :: cnode()) -&gt; Hscore :: number().
h_score(Current, Goal) -&gt;
    dist_between(Current, Goal).

%% @doc Returns the distance from `Current&#039; node to `Goal&#039; node
-spec dist_between(cnode(), cnode()) -&gt; Distance :: number().
dist_between(Current, Goal) -&gt;
    {X1, Y1} = Current,
    {X2, Y2} = Goal,
    abs((X2-X1)) + abs((Y2-Y1)).

%% @doc Returns the best next step from `OpenSetAsList&#039;
%% TODO: May be optimized by making OpenSet an ordered set.
-spec best_step(OpenSetAsList :: list(cnode()), Fscore :: dict(), BestNodeTillNow :: cnode() | none, BestCostTillNow :: number() | infinity) -&gt; cnode().
best_step([H|Open], Score, none, infinity) -&gt;
    V = dict:fetch(H, Score),
    best_step(Open, Score, H, V);

best_step([], _Score, Best, _BestValue) -&gt;
    Best;

best_step([H|Open], Score, Best, BestValue) -&gt;
    Value = dict:fetch(H, Score),
    case Value &lt; BestValue of
        true -&gt;
            best_step(Open, Score, H, Value);
        false -&gt;
            best_step(Open, Score, Best, BestValue)
    end.

%% @doc Returns the neighbour nodes of `Node&#039;, and excluding its `Parent&#039;.
-spec neighbour_nodes(cnode(), cnode() | none) -&gt; list(cnode()).
neighbour_nodes(Node, Parent) -&gt;
    {X, Y} = Node,
    [
     {XX, YY} ||
     {XX, YY} &lt;- [{X-1, Y}, {X, Y-1}, {X+1, Y}, {X, Y+1}],
     {XX, YY} =/= Parent,
     XX &gt;= ?MINX,
     YY &gt;= ?MINY,
     XX =&lt; ?MAXX,
     YY =&lt; ?MAXY
    ].

%% @doc Scans the `Neighbours&#039; of `BestStep&#039;, and adds/updates the Scores and CameFrom dicts accordingly.
-spec scan(
        Goal :: cnode(),
        BestStep :: cnode(),
        Neighbours :: list(cnode()),
        NextOpen :: set(),
        NextClosed :: set(),
        Fscore :: dict(),
        Gscore :: dict(),
        CameFrom :: dict()
       ) -&gt;
    {NewOpen :: set(), NewF :: dict(), NewG :: dict(), NewFrom :: dict()}.
scan(_Goal, _X, [], Open, _Closed, F, G, From) -&gt;
    {Open, F, G, From};
scan(Goal, X, [Y|N], Open, Closed, F, G, From) -&gt;
    case sets:is_element(Y, Closed) of
        true -&gt;
            scan(Goal, X, N, Open, Closed, F, G, From);
        false -&gt;
            G0 = dict:fetch(X, G),
            TrialG = G0 + dist_between(X, Y),
            case sets:is_element(Y, Open) of
                true -&gt;
                    OldG = dict:fetch(Y, G),
                    case TrialG &lt; OldG of
                        true -&gt;
                            NewFrom = dict:store(Y, X, From),
                            NewG    = dict:store(Y, TrialG, G),
                            NewF    = dict:store(Y, TrialG + h_score(Y, Goal), F), % Estimated total distance from start to goal through y.
                            scan(Goal, X, N, Open, Closed, NewF, NewG, NewFrom);
                        false -&gt;
                            scan(Goal, X, N, Open, Closed, F, G, From)
                    end;
                false -&gt;
                    NewOpen = sets:add_element(Y, Open),
                    NewFrom = dict:store(Y, X, From),
                    NewG    = dict:store(Y, TrialG, G),
                    NewF    = dict:store(Y, TrialG + h_score(Y, Goal), F), % Estimated total distance from start to goal through y.
                    scan(Goal, X, N, NewOpen, Closed, NewF, NewG, NewFrom)
            end
    end.

%% @doc Reconstructs the calculated path using the `CameFrom&#039; dict
-spec reconstruct_path(dict(), cnode()) -&gt; list(cnode()).
reconstruct_path(CameFrom, Node) -&gt;
    case dict:fetch(Node, CameFrom) of
        none -&gt;
            [Node];
        Value -&gt;
            [Node | reconstruct_path(CameFrom, Value)]
    end.</code></pre>
  </figure>
<h3>Notes</h3>
<ul><li><p>Variables <code>MINX</code>, <code>MINY</code>, <code>MAXX</code> and <code>MAXY</code> can be modified to increase the size of the map. The function <code>neighbour_nodes/2</code> can be modified to add obstacles.</p></li><li><p>To test, enter in erlang shell:</p></li></ul><figure>
  <pre><code class="language-erlang">c(astar).
astar:astar({1, 1}, {10, 10}).</code></pre>
  </figure>
<ul><li><p>The <code>cnode()</code> structure represents some sort of coordinate. To use some other structure, the functions <code>neighbour_nodes/2</code>, <code>h_score/2</code>, and <code>distance_between/2</code> have to be modified for the new structure.</p></li><li><p>The current heuristic does not penalize for turns, so the resultant 
path tends to follow a diagonal looking shape. For correcting this, 
either diagonal movements can be allowed (by modifying the neighbours 
function), or turning could be penalized in the heuristic function 
(current direction would have to be tracked).</p></li></ul>]]></content:encoded>
    <comments>https://srijan.ch/basic-implementation-of-a-in-erlang#comments</comments>
    <slash:comments>0</slash:comments>
  </item><item>
    <title>Erlang Profiling Tips</title>
    <description><![CDATA[Some erlang profiling tips / tools I've come across]]></description>
    <link>https://srijan.ch/erlang-profiling-tips</link>
    <guid isPermaLink="false">6030d3dab5e0920001f557cc</guid>
    <category><![CDATA[erlang]]></category>
    <category><![CDATA[development]]></category>
    <dc:creator>Srijan Choudhary</dc:creator>
    <pubDate>Wed, 20 Feb 2013 00:00:00 +0000</pubDate>
    <content:encoded><![CDATA[<p>I have been using erlang recently for some of my work and private 
projects, and so I have decided to write about a few things there were 
hard to discover.</p> <p>Profiling is an essential part of programming in erlang. <a href="http://www.erlang.org/doc/efficiency_guide/profiling.html">Erlang's efficiency guide</a> says:</p><blockquote>
  Even experienced software developers often guess wrong about where the performance bottlenecks are in their programs.<br>Therefore, profile your program to see where the performance bottlenecks are and concentrate on optimizing them.  </blockquote>
<h2>Using profiling tools in releases (using rebar/reltool)</h2>
<p>So, after finishing a particularly complicated bit of code, I wanted 
to see how well it performed, and figure out any bottlenecks.</p> <p>But, I hit a roadblock. Following the <a href="http://www.erlang.org/doc/man/fprof.html">erlang manual for fprof</a>, I tried to start it, but it wouldn't start and was giving the error:</p><figure>
  <pre><code class="language-erlang">** exception error: undefined function fprof:start/0</code></pre>
  </figure>
<p>To make this work, I had to add <code>tools</code> to the list of apps in my <code>reltool.config</code> file. After adding this and regenerating, it all works.</p><h2>Better visualization of fprof output</h2>
<p>So, after I got the fprof output, I discovered it was a long file with a lot of data, and no easy way to make sense of it.</p> <p>I tried using <a href="http://www.erlang.org/doc/man/eprof.html">eprof</a> (which gives a condensed output), and it helped, but I was still searching for a better way.</p> <p>Then I stumbled upon <a href="http://stackoverflow.com/questions/14242607/eprof-erlang-profiling#comment19935708_14242607">a comment on stackoverflow</a>, which linked to <a href="https://github.com/isacssouza/erlgrind">erlgrind - a script to convert the fprof output to callgrind output</a>, which can be visualized using <a href="http://kcachegrind.sourceforge.net/">kcachegrind</a> or some such tool.</p><h3>Software Links</h3>
<ul><li><a href="http://www.erlang.org/doc/efficiency_guide/profiling.html">Erlang Profiling Guide</a></li><li><a href="https://github.com/isacssouza/erlgrind">Erlgrind</a></li><li><a href="http://kcachegrind.sourceforge.net/">Kcachegrind</a></li></ul>]]></content:encoded>
    <comments>https://srijan.ch/erlang-profiling-tips#comments</comments>
    <slash:comments>0</slash:comments>
  </item></channel>
</rss>
