<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ellen Chisa</title>
    <description>The latest articles on DEV Community by Ellen Chisa (@ellenchisa).</description>
    <link>https://dev.to/ellenchisa</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F203588%2F33b4ed4b-5e30-4af3-a667-d2bf694aead0.jpeg</url>
      <title>DEV Community: Ellen Chisa</title>
      <link>https://dev.to/ellenchisa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ellenchisa"/>
    <language>en</language>
    <item>
      <title>Shortcutting a Standard Library</title>
      <dc:creator>Ellen Chisa</dc:creator>
      <pubDate>Thu, 07 May 2020 16:47:25 +0000</pubDate>
      <link>https://dev.to/darklang/shortcutting-a-standard-library-4p95</link>
      <guid>https://dev.to/darklang/shortcutting-a-standard-library-4p95</guid>
      <description>&lt;p&gt;&lt;em&gt;Coauthored by &lt;a href="https://jceipek.com" rel="noopener noreferrer"&gt;Julian Ceipek&lt;/a&gt; and &lt;a href="https://dev.to/paulbiggar"&gt;Paul Biggar&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We recently decided to significantly expand &lt;a href="https://darklang.com" rel="noopener noreferrer"&gt;Dark&lt;/a&gt;'s standard library. While our standard library has a lot of functionality for the Dark "framework", including HTTP, worker/queue, and &lt;a href="https://medium.com/darklang/compiling-dark-to-sql-bb8918d1acdd" rel="noopener noreferrer"&gt;datastore functions&lt;/a&gt;, we were a little short on normal functions you'd expect from a "batteries included" language, such as functions for math and manipulating standard datatypes like lists, dictionaries, numbers, and strings.&lt;/p&gt;

&lt;p&gt;As a shortcut to ship faster, we decided to take our lead from the Elm standard library. Elm's standard library is well-designed, with significant thought given to usability.  Dark and Elm are both intended for a similar audience: frontend developers using functional languages for the first time. The Dark and Elm languages share many commonalities, with Dark taking influence from Elm and other similar languages like OCaml. Really, Elm has the perfect standard library from which to take inspiration!&lt;/p&gt;

&lt;p&gt;This also isn't our first rodeo with the Elm standard library: Dark was written in Elm for &lt;a href="https://medium.com/darklang/philip2-an-elm-to-reasonml-compiler-a210aaa6cd04" rel="noopener noreferrer"&gt;its first year&lt;/a&gt;, and we used Elm's standard library as an influence for our &lt;a href="https://github.com/darklang/tablecloth" rel="noopener noreferrer"&gt;tablecloth&lt;/a&gt; OCaml standard library. &lt;/p&gt;

&lt;p&gt;Given these similarities and our prior experience, expanding Dark's standard library using Elm's library as an influence seemed trivial. However, minor semantic differences between Elm and Dark led to significant subtleties in how this worked in practice.&lt;/p&gt;

&lt;h1&gt;
  
  
  Language differences
&lt;/h1&gt;

&lt;p&gt;In many cases we needed to implement different behavior or function signatures from the Elm functions we were looking at. All of these boiled down to subtle language differences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pipeline ordering
&lt;/h2&gt;

&lt;p&gt;Elm supports pipelining as a first-class language feature. For example, in Elm you can write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the same as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most Elm functions are designed to allow easy pipelining: the main value that you're operating on goes last. Paul has spent a significant amount of time writing Clojure, which uses pipelining but does not adhere as strongly to this principle, and it's one of the many things that makes Elm a delight to use.&lt;/p&gt;

&lt;p&gt;While Dark is also designed for pipelining, we pipe into the first position instead. Because we pipe into the first position, we obviously need to change the parameter order to get the same effect.&lt;/p&gt;

&lt;p&gt;In Dark,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocaml"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is a shorthand for&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocaml"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But it goes a bit further than that. Elm's function names often take into account the parameter order. For example, in the following cases, Elm uses the suffixes "by", "base" and "with", referring to the first argument.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;remainderBy&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;  &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;--                       [ -1,  0, -3, -2, -1,  0,  1,  2,  3,  0,  1 ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;logBase&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;logBase&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;sortWith&lt;/span&gt; &lt;span class="n"&gt;flippedComparison&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;flippedComparison&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;compare&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
      &lt;span class="kt"&gt;LT&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;GT&lt;/span&gt;
      &lt;span class="kt"&gt;EQ&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;EQ&lt;/span&gt;
      &lt;span class="kt"&gt;GT&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;LT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Dark's versions we ended up going with &lt;code&gt;List::sortByComparator&lt;/code&gt; instead of &lt;code&gt;List.sortWith&lt;/code&gt;,  and &lt;code&gt;Int::remainder&lt;/code&gt; for &lt;code&gt;remainerBy&lt;/code&gt; in order to match the naming to the parameter order required by the different pipeline behavior. We forgot to add a &lt;code&gt;log&lt;/code&gt; function, but we'd probably have called it &lt;code&gt;Int::log&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Namespaces
&lt;/h2&gt;

&lt;p&gt;Elm puts a lot of math functions in the global namespace, including &lt;code&gt;abs&lt;/code&gt; and &lt;code&gt;pi&lt;/code&gt;. Having small recognizable names for math allows you to understand a complex expression more quickly and effectively than if it were written out, and so these short names can often make sense. When we weigh the design goals of Dark however, it starts to look quite different.&lt;/p&gt;

&lt;h3&gt;
  
  
  Autocomplete
&lt;/h3&gt;

&lt;p&gt;Dark developers are learning the Dark language and the Dark editor in tandem. As such, we rely heavily on autocomplete to make the standard library discoverable. Putting all functions in module namespaces makes it easy to discover functions, so it makes sense to put these functions in either the &lt;code&gt;Math&lt;/code&gt; namespace, or a relevant namespace like &lt;code&gt;Int&lt;/code&gt; or &lt;code&gt;Float&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generic Classes
&lt;/h3&gt;

&lt;p&gt;Elm has a &lt;code&gt;number&lt;/code&gt; typeclass which Dark doesn't have yet, which means that in Elm, &lt;code&gt;abs&lt;/code&gt; can work with both &lt;code&gt;Ints&lt;/code&gt; and &lt;code&gt;Floats&lt;/code&gt;. Putting these functions in modules allows us to distinguish based on type: we have &lt;code&gt;Int::absoluteValue&lt;/code&gt; and &lt;code&gt;Float::absoluteValue&lt;/code&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Function Length
&lt;/h3&gt;

&lt;p&gt;Finally, we decided not to use short function names. We perceive that Dark is not typically used for complex math expressions, so there isn't as much value in making function names short. Math expressions are much more common in frontends, for which Elm is designed.&lt;/p&gt;

&lt;p&gt;We do have plans to support short names by providing control over how our editor displays names, or to increase function discoverability by aliasing different names in our autocomplete, but we haven't fleshed out those ideas yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Safety and Usability: Pick Two
&lt;/h2&gt;

&lt;p&gt;Standard libraries need to manage a fine line between safety and ease of use. Elm has to walk this line, and not all of its functions come down on the same side of it. For example, Elm's &lt;code&gt;String.uncons&lt;/code&gt; returns the unwieldy &lt;code&gt;Maybe (Char, String)&lt;/code&gt;. Meanwhile, &lt;code&gt;List.map2&lt;/code&gt; silently drops elements from the longer list when the lists have different lengths.&lt;/p&gt;

&lt;p&gt;Dark tries to support both safety and ease-of-use where possible. We built a feature called &lt;a href="https://medium.com/darklang/real-problems-with-functional-languages-efe668c5264a" rel="noopener noreferrer"&gt;the "Error Rail"&lt;/a&gt;, which automatically unwraps Options and Results to make them easier to use during the early, exploratory stages of coding, when writing something quickly and simply is more important than handling every eventuality. Later, when the coder wants to be sure that their code works in every special case, they can "take the function off the error rail" to handle edge cases.&lt;/p&gt;

&lt;p&gt;This affects the design of Dark's &lt;code&gt;List::map2&lt;/code&gt;. This function takes two lists and calls a function on arguments in the same positions in both lists. When the lists are different lengths, should we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;choose ease-of-use by making it just work (by unsafely ignoring extra elements in the longer list &lt;a href="https://package.elm-lang.org/packages/elm/core/latest/List#map2" rel="noopener noreferrer"&gt;like Elm does&lt;/a&gt;)?&lt;/li&gt;
&lt;li&gt;or choose the safety of making sure the programmer knows when the lists are different length (at the cost of wrapping the return value in an &lt;code&gt;Option&lt;/code&gt; that the programmer has to handle, which is similar to what &lt;a href="https://ocaml.janestreet.com/ocaml-core/latest/doc/base/Base/List/#val-map2" rel="noopener noreferrer"&gt;OCaml Core does&lt;/a&gt;)?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because of the error rail, implementing &lt;code&gt;List::map2&lt;/code&gt; to return an &lt;code&gt;Option&lt;/code&gt; makes the common case of the lists having equal lengths easy:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F0%2AToAJpeJzlUNzkMxZ" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F0%2AToAJpeJzlUNzkMxZ" alt="https://miro.medium.com/max/1400/0*ToAJpeJzlUNzkMxZ"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the author knows the lists will never differ in length, they can stop there. Alternatively, they can take the function off the rail to handle the &lt;code&gt;Option&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F0%2AOopR-o4GP16VDGde" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F0%2AOopR-o4GP16VDGde" alt="https://miro.medium.com/max/1400/0*OopR-o4GP16VDGde"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And if they &lt;em&gt;want&lt;/em&gt; the behavior of dropping elements from the longer list, they can instead use our new &lt;code&gt;List::map2shortest&lt;/code&gt; (when the coder goes to use &lt;code&gt;map2&lt;/code&gt;, the autocomplete will present both options so this is discoverable):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F0%2Aageng1dAAygRYbEG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F0%2Aageng1dAAygRYbEG" alt="https://miro.medium.com/max/1400/0*ageng1dAAygRYbEG"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  NaNs and Infinity
&lt;/h2&gt;

&lt;p&gt;There are similar problems around floating point. A goal in Dark is to not have &lt;code&gt;NaN&lt;/code&gt; (&lt;code&gt;NaN&lt;/code&gt; is the "not a number" floating point value that shows up when you perform floating point math with indeterminate results, like &lt;code&gt;0.0/0.0&lt;/code&gt;). Since Dark has structured error handling with a &lt;code&gt;Result&lt;/code&gt; type, why should it also support implicit errors via &lt;code&gt;NaN&lt;/code&gt;s?&lt;/p&gt;

&lt;p&gt;Elm does have &lt;code&gt;NaN&lt;/code&gt;s though, and so when we designed our floating-point functions, they had both different behavior in the case of NaNs, they also had different signatures (returning &lt;code&gt;Result&lt;/code&gt;s instead of plain &lt;code&gt;Float&lt;/code&gt;s).&lt;/p&gt;

&lt;p&gt;So we chose safety, and allowed the Error Rail to provide ease-of-use, right? Alas not. Unfortunately, we discovered that we don't support the error rail for operators yet, which makes it hard to use &lt;code&gt;Result&lt;/code&gt;s for arithmetic.  In addition, the error rail in its current manifestation is really about making prototyping easy, but you can't actually handle errors without taking values off the rail. This makes using it for something like arithmetic cumbersome. Alas, we had to shelve this for now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous Language delivery
&lt;/h2&gt;

&lt;p&gt;We don't believe we got everything right in this round of the standard library. Fortunately, we designed Dark to be &lt;a href="https://medium.com/darklang/how-dark-deploys-code-in-50ms-771c6dd60671" rel="noopener noreferrer"&gt;easy to change&lt;/a&gt;, and each of the functions we added are individually versioned. This allows us to create new versions of the functions later, which developers using Dark can individually choose to upgrade.&lt;/p&gt;

&lt;h1&gt;
  
  
  Results
&lt;/h1&gt;

&lt;p&gt;Over the course of the project we added 61 functions, in some cases deprecating old, poorly-named functions. In total, we now have 125 "basic" functions in the modules &lt;code&gt;Bool&lt;/code&gt;, &lt;code&gt;Float&lt;/code&gt;,&lt;code&gt;Int&lt;/code&gt;, &lt;code&gt;Math&lt;/code&gt;, &lt;code&gt;Dict&lt;/code&gt;, &lt;code&gt;List&lt;/code&gt;, &lt;code&gt;Option&lt;/code&gt;, &lt;code&gt;Result&lt;/code&gt;, and &lt;code&gt;String&lt;/code&gt; (this does not include &lt;code&gt;HTTP&lt;/code&gt;, &lt;code&gt;DB&lt;/code&gt;, and other Dark "framework" modules).&lt;/p&gt;

&lt;p&gt;Of these 125 functions, we ended up using different function names from Elm in 44 cases, different parameter order in 30 cases, and different behavior in at least 10 cases.&lt;/p&gt;

&lt;p&gt;Elm has a great standard library, and it was a good starting point for expanding Dark. The subtleties of the language semantics and goals has a big impact on the standard library, and we discovered we needed to have good understanding of the differences between Elm and Dark as a result.&lt;/p&gt;

&lt;h1&gt;
  
  
  Learn More
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.google.com/forms/d/e/1FAIpQLSfAKkhMqcxnsFYoUMmGPci--bV6qCfCx0k3mXNEezJQrqzj6w/viewform?usp=sf_link" rel="noopener noreferrer"&gt;Come chat with Paul Biggar&lt;/a&gt;, our CTO, at an AMA on Friday, May 8th.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://darklang.com/signup?2c03858d-b6ae-4ef9-854c-f770ea52760d" rel="noopener noreferrer"&gt;Give Dark a try&lt;/a&gt; to see our standard library in action. (limited spots available)&lt;/li&gt;
&lt;li&gt;Once you have your Dark account, &lt;a href="http://darklang.com/a/sample-stdlib" rel="noopener noreferrer"&gt;check out our standard library samples&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Spin up a Slack app in seconds with Dark</title>
      <dc:creator>Ellen Chisa</dc:creator>
      <pubDate>Wed, 29 Apr 2020 18:34:52 +0000</pubDate>
      <link>https://dev.to/darklang/spin-up-a-slack-app-in-seconds-with-dark-3h71</link>
      <guid>https://dev.to/darklang/spin-up-a-slack-app-in-seconds-with-dark-3h71</guid>
      <description>&lt;p&gt;Seconds is a &lt;em&gt;bit&lt;/em&gt; of an exaggeration, but we've made it possible to build a full Slack app in less than an hour. &lt;a href="https://darklang.com/signup?05b46f1e-153b-4f6f-9926-b50060a994f3"&gt;You can jump right in&lt;/a&gt; (limited number of accounts available - if the link has expired, click &lt;a href="https://darklang.com/beta"&gt;here&lt;/a&gt; to join the waitlist.)&lt;/p&gt;

&lt;p&gt;How? Our very first package. &lt;/p&gt;

&lt;p&gt;We've created and released &lt;a href="https://darklang.github.io/docs/slack-apps/slack-packages"&gt;a set of functions&lt;/a&gt; to make the best possible Slack API experience. No more writing an OAuth implementation from scratch - it's just one line, and you can see it working right away.&lt;/p&gt;

&lt;p&gt;Here's a peek under the hood:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5Hy10rzn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/0%2AyKkenT1m4kBgd8s-" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5Hy10rzn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/0%2AyKkenT1m4kBgd8s-" alt="https://miro.medium.com/max/1400/0*yKkenT1m4kBgd8s-"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything else is just as easy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trigger /commands to an API endpoint just by configuring in Slack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5UE7__kW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/0%2AFdBNGtGfPbpeiLQp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5UE7__kW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/0%2AFdBNGtGfPbpeiLQp" alt="https://miro.medium.com/max/1400/0*FdBNGtGfPbpeiLQp"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;@mention a bot and process the payload live&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--73PtzEs2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/0%2AvikQRLTufMjosvJk" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--73PtzEs2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/0%2AvikQRLTufMjosvJk" alt="https://miro.medium.com/max/1400/0*vikQRLTufMjosvJk"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Find a list of channels&lt;/li&gt;
&lt;li&gt;Post messages to any channel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not sure where to start?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jump right in with the first slack App tutorial. You can set up a quick app in &amp;lt;5 minutes: &lt;a href="https://darklang.github.io/docs/slack-apps/slack-intro"&gt;https://darklang.github.io/docs/slack-apps/slack-intro&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Look at code for existing Slack applications built in Dark: &lt;a href="https://darklang.com/a/sample-magiceightball"&gt;https://darklang.com/a/sample-magiceightball&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Check out &lt;a href="https://snipy.io"&gt;snipy.io&lt;/a&gt; and &lt;a href="https://summit.work/"&gt;Summit.Work&lt;/a&gt;, companies built by developers who are using Dark for the backend. We've also seen people build OKR trackers, ice breaker prompts, show their app store reviews in engineering channels, and more!&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.google.com/forms/d/e/1FAIpQLSfphGMiOw-nm30SYuCC-EeMoUV5dB43WRcCQorfOZQ7ClpC7A/viewform?usp=sf_link"&gt;Come to our in person walkthrough&lt;/a&gt; on Friday at 7am PST/10am EST/3pm BST or 10:30am PST/1:30pm EST/6:30pm BST.&lt;/li&gt;
&lt;li&gt;Follow a longer tutorial to build a useful Slack integration: &lt;a href="https://darklang.github.io/docs/slack-apps/tutorials/new-trello-card"&gt;Trello integration&lt;/a&gt; and a &lt;a href="https://darklang.github.io/docs/slack-apps/tutorials/channel-check"&gt;bot that posts when new channels are created&lt;/a&gt;. We're working on more all the time, and happily invite our community to submit their own by submitting &lt;a href="https://github.com/darklang/docs"&gt;pull requests to our documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://darklang.com/slack-invite"&gt;Join our community&lt;/a&gt; (yes, it's on Slack!) to connect with other Dark developers.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>darklang</category>
      <category>slackapp</category>
      <category>api</category>
    </item>
    <item>
      <title>So you want to post messages to Slack</title>
      <dc:creator>Ellen Chisa</dc:creator>
      <pubDate>Thu, 09 Jan 2020 18:51:33 +0000</pubDate>
      <link>https://dev.to/darklang/so-you-want-to-post-messages-to-slack-3jem</link>
      <guid>https://dev.to/darklang/so-you-want-to-post-messages-to-slack-3jem</guid>
      <description>&lt;p&gt;Want to get started building a Slack app, but not sure what you need? The Slack API provides three easy ways to programmatically post messages. &lt;/p&gt;

&lt;p&gt;There are three easy scenarios:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Posting messages in a specific channel (say #engineering).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you know what channel you want to post to, you can set up an incoming webhook. (An example of this would be wanting to share reviews from an AppStore in your #engineering channel). You'll be able to post at any point, and everyone in the channel will see it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Responding privately to a specific user.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want to post something for a user on demand, the best way is to set up a /command. When the user calls it, regardless of channel, you'll receive a response_url parameter and can publish back to them. (For example, letting users ask a &lt;a href="https://vimeo.com/380770154"&gt;Magic Eight Ball&lt;/a&gt;). They'll be able to use this from any channel. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Something else&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For anything other than these two scenarios, use the &lt;a href="https://api.slack.com/methods/chat.postMessage"&gt;chat.postMessage&lt;/a&gt; (make sure you have a write scope defined in the OAuth/Permissions section). This will allow your app to publish to any channel, for all users to see!&lt;/p&gt;

&lt;p&gt;In any of these cases, if you need fancier messages, the &lt;a href="https://api.slack.com/tools/block-kit-builder"&gt;Slack Block Kit Builder&lt;/a&gt; lets you write/get real JSON, while also being able to see what your message would look like. You should be able to try these methods out wherever your favorite place is to set up an API! &lt;/p&gt;

&lt;p&gt;Want to get started without a bunch of other set up? Join the &lt;a href="https://darklang.com/beta"&gt;Dark Beta&lt;/a&gt; and mention dev.to. &lt;/p&gt;

&lt;p&gt;This is all you need to do to get these three options going in Dark:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dEQu6Ce2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/jr8wwptwre5yju9j2oht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dEQu6Ce2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/jr8wwptwre5yju9j2oht.png" alt="Dark Handlers"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>slack</category>
      <category>api</category>
      <category>darklang</category>
    </item>
  </channel>
</rss>
