<?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>Forem: Paweł Stadnicki</title>
    <description>The latest articles on Forem by Paweł Stadnicki (@pstadnicki).</description>
    <link>https://forem.com/pstadnicki</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%2F702360%2Feca9e1f8-e3a1-4b8f-8e46-fb71223e567d.jpg</url>
      <title>Forem: Paweł Stadnicki</title>
      <link>https://forem.com/pstadnicki</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/pstadnicki"/>
    <language>en</language>
    <item>
      <title>What F# Knows About Functors and What Comes Next</title>
      <dc:creator>Paweł Stadnicki</dc:creator>
      <pubDate>Fri, 26 Dec 2025 20:29:43 +0000</pubDate>
      <link>https://forem.com/pstadnicki/what-f-knows-about-functors-and-what-comes-next-2i59</link>
      <guid>https://forem.com/pstadnicki/what-f-knows-about-functors-and-what-comes-next-2i59</guid>
      <description>&lt;p&gt;This post is a short, opinionated reflection on &lt;strong&gt;one thing&lt;/strong&gt; that feels most notably missing in F# today. It provides brief background, references recent discussions on why this gap exists, and ends with a teaser of a possible solution that we will shortly have in our arsenal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When F# Alone Is Not Enough&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s look at something we already have—even if we don’t quite treat it as a first-class citizen. Let's look without precise category-theory definitions, just an intuitive picture.&lt;/p&gt;

&lt;p&gt;You may have heard of a &lt;strong&gt;Functor&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Functor is a great name for a dog.&lt;br&gt;
In programming, you can leave one alone for days&lt;br&gt;
and it will still behave exactly the same, obeying all the laws.&lt;/p&gt;

&lt;p&gt;As an F# developer, if you want to play with a Functor, you usually have to name your dog yourself (or your &lt;a href="https://typelevel.org/cats/" rel="noopener noreferrer"&gt;cat&lt;/a&gt; — but that would make the metaphor silly). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhbz8g22z86j16amo37w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhbz8g22z86j16amo37w.png" alt=" " width="799" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To be precise: such a pet does exist in F#. But it remains unnamed — unless you use the &lt;a href="https://fsprojects.github.io/FSharpPlus/" rel="noopener noreferrer"&gt;FSharpPlus&lt;/a&gt; library as a kind of dog collar. And while that helps, it’s still not quite the same.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The behavior is present; the abstraction is not.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In F#, the idea of a functor survives without the name — an example of how far the language goes, and where it deliberately stops.&lt;/p&gt;

&lt;p&gt;This is not a complaint. It’s a reflection on growth — of the language, and of its ecosystem.&lt;/p&gt;

&lt;p&gt;There are things that are simply not expressible in F# today. &lt;br&gt;
The most important of these is the ability to abstract over type constructors themselves.&lt;/p&gt;

&lt;p&gt;Full &lt;a href="https://serokell.io/blog/kinds-and-hkts-in-haskell" rel="noopener noreferrer"&gt;HKT&lt;/a&gt; support lets you name, pass around, store, compose, and reason about abstractions—not just use them implicitly through functions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgajio5bq2kll2f3wgzws.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgajio5bq2kll2f3wgzws.png" alt=" " width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In F#, we can rely on functorial behavior (map on Option, List, Async, etc.), but we cannot name it, quantify over it, or require it in our own APIs.&lt;/p&gt;

&lt;p&gt;Changing a language at its core—for example, by redesigning generics—is an extremely disruptive, breaking change. Scala is a notable example here: because it was designed from the ground up to support HKTs, it was able to implement type classes through its implicits mechanism.&lt;br&gt;
F#, by contrast, is built on .NET’s reified generics, which prioritize runtime performance and cross-language compatibility, but lack the native infrastructure to abstract over containers (F[T]) without complex workarounds.&lt;/p&gt;

&lt;p&gt;Don Syme, in his well-known position on type classes, writes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I don’t want F# to be the kind of language where the most empowered person in the Discord chat is the person who knows the most category theory or abstract algebra.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(Please read the &lt;a href="https://dsyme.net/2021/09/09/my-position-on-type-classes/" rel="noopener noreferrer"&gt;full article&lt;/a&gt;; this excerpt is intentionally selective and used here only to frame the discussion.)&lt;/p&gt;

&lt;p&gt;That position is understandable — and arguably the right one for a mainstream language.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And what about creating a new language altogether&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;As Anders Hejlsberg, the creator of C# and TypeScript, &lt;a href="https://www.youtube.com/watch?v=GMWJceUTxuk" rel="noopener noreferrer"&gt;recently noted&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Introducing new programming languages in the AI era is inherently disadvantaged: the “best” language for AI is the one it has seen the most.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;So, to tackle today's complexities, maybe indeed we should revisit Category Theory?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yet another CT geek, huh? I'm still learning, but the past few months—after years of trying and abandoning the subject—have brought me to a realization: you either know Category Theory well enough to use it confidently, or you don't use it at all.&lt;/p&gt;

&lt;p&gt;A DSL with real HKT support would allows us to define behavior once and lift it across structure. It lets us reason about effects without committing to execution, and about context without sequencing. That’s why functors—and, naturally, comonads—are often the right place to start when designing complex effect systems. They operate at a more fundamental layer than monads: the layer where the meaning of context is defined, before effects are sequenced.&lt;/p&gt;

&lt;p&gt;With HKTs, a lot of CT will become more obvious. Almost boring, but surprisingly enjoyable.&lt;/p&gt;

&lt;p&gt;And that’s the point.&lt;/p&gt;

&lt;h2&gt;
  
  
  So Where Does This Leave Us ?
&lt;/h2&gt;

&lt;p&gt;What does not emerge in the open often continues to grow elsewhere.&lt;/p&gt;

&lt;p&gt;In 2026, we’ll be able to use more ideas from Category Theory in practice—not by escaping language constraints, but by working with them deliberately. This will happen through a DSL/language being built at BLP: written in F# and extensible with F#.&lt;/p&gt;

&lt;p&gt;I have the privilege of being the dumbest person in that room—and of getting to play with these ideas early.&lt;/p&gt;

&lt;p&gt;This post is not a reveal of that DSL yet, but simply a short opening note. The concrete parts, with proper credit to authors will be discussed starting in January.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5617xd3voto0i5hlfu0n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5617xd3voto0i5hlfu0n.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I'm alone in this opinion ?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This year’s &lt;a href="https://sergeytihon.com/2025/11/03/f-advent-calendar-in-english-2025/" rel="noopener noreferrer"&gt;Advent of F# calendar&lt;/a&gt; reflects a noticeable shift. The majority of contributions focus on domain modeling, types, language tooling (LSPs), and even programming language design, rather than MCP-related topics. At the same time, Tomas Petricek—the long-time advocate of effect systems—continues to deliver excellent &lt;a href="https://www.youtube.com/playlist?list=PLRBVoLoCYzDML8e9g58f6zb-faG1rMHIJ" rel="noopener noreferrer"&gt;lessons&lt;/a&gt; on building small, well-structured systems in F#. There is also a promising &lt;a href="https://www.amazon.com/Book-Functions-Abstract-Category-Functional/dp/1718501609" rel="noopener noreferrer"&gt;book&lt;/a&gt; coming next year, The Book of Functions, which fits perfectly into this broader reflection.&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>discuss</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Flying with F#</title>
      <dc:creator>Paweł Stadnicki</dc:creator>
      <pubDate>Sat, 09 Dec 2023 15:54:33 +0000</pubDate>
      <link>https://forem.com/pstadnicki/flying-with-f-8bp</link>
      <guid>https://forem.com/pstadnicki/flying-with-f-8bp</guid>
      <description>&lt;p&gt;This blog post is a part of the awesome &lt;a href="https://sergeytihon.com/2023/10/28/f-advent-calendar-in-english-2023/" rel="noopener noreferrer"&gt;F# Advent Calendar in English&lt;/a&gt; organized by Sergey Tihon, an annual collection of more than 30 posts, that could form a book "F# in Practice" by the community.&lt;/p&gt;

&lt;p&gt;The source code for the presented experiments can be found &lt;a href="https://github.com/PawelStadnicki/flying-with-fsharp" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The topic&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;How far are F# devs from creating sth cool?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Sometimes it is just a single JS binding. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In my spare time, I enjoy working on Proof of Concept (POC) projects.&lt;/p&gt;

&lt;p&gt;I select something that I find interesting, quickly develop a Proof of Concept, and then move on to the next one.&lt;/p&gt;

&lt;p&gt;I believe that by creating around 20 POCs, I can eventually build an interesting product from a few of them. It's a reverse approach to applying technology. Normally, you start with a specific need that technology should address, but in my case, I begin with the technology itself.&lt;/p&gt;

&lt;p&gt;Certainly, this approach may not be the most conventional or lucrative one, but I find it rewarding nonetheless.&lt;/p&gt;

&lt;p&gt;This time I present how to combine F# with Google 3D Photorealistic tiles.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1f6oruazd1uhp34nlts.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1f6oruazd1uhp34nlts.gif" alt=" " width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I demonstrate the seamless integration of key elements. With each animation frame, you can harness values like location, bearing, zoom, and pitch, and transform these into captivating experiences - from rotating around a locale to following a route, or even simulating a drone flight. Elevate your website with a map that's not just dynamic but truly alive!&lt;/p&gt;

&lt;p&gt;Start by obtaining your &lt;a href="https://developers.google.com/maps/documentation/tile/get-api-key" rel="noopener noreferrer"&gt;own API key&lt;/a&gt; for the 3D tiles. While this product has transitioned from a preview to a paid service, you can receive a generous $200 monthly credit, giving you ample freedom to explore its features. Beyond this, the cost is $6 per 1,000 'root requests'. For high-traffic applications, this means $6,000 for every million views. It's important to factor this into your planning. For more details, be sure to review the documentation thoroughly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The best thing about tiles in general is that all you need is to host them and move around with some sort of engine. Obviously, all of these engines are inherently connected to JavaScript. Fortunately, we have Fable, so the only challenge is to find a library, for each we can write binding easily.&lt;/p&gt;

&lt;p&gt;I noticed on Twitter that &lt;a href="https://studio.foursquare.com/home" rel="noopener noreferrer"&gt;Foursquare Studio&lt;/a&gt; has the option to add these tiles very easily:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4srxv36kg4t6rkbnwrz9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4srxv36kg4t6rkbnwrz9.png" alt=" " width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I knew that this tool is built with DeckGL, so I checked their docs and ... there is a very simple example (&lt;a href="https://deck.gl/examples/google-3d-tiles" rel="noopener noreferrer"&gt;https://deck.gl/examples/google-3d-tiles&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;Translation of this example to Fable looks like (one of the possible approaches):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fplcb3q5evioua7kb1kq2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fplcb3q5evioua7kb1kq2.png" alt=" " width="723" height="196"&gt;&lt;/a&gt;&lt;br&gt;
And the actual binding:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7962qwthp1fdiho0h4h9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7962qwthp1fdiho0h4h9.png" alt=" " width="800" height="529"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;DeckGL just expects view state object with certain values to be used in the projection (and animations):&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiu8yi2g4c66gcyptv6z8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiu8yi2g4c66gcyptv6z8.png" alt=" " width="680" height="177"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we are using React, all we have to do is update this object with the setState or Elmish hook. In my experiments, I'm using the latter.&lt;/p&gt;

&lt;p&gt;The PoC has a simple dashboard, you can check the implementation to see how appropriate values are updated with Elmish style:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flne6jk182ou8eq7b29a1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flne6jk182ou8eq7b29a1.png" alt=" " width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also provided 4 simple animations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;move to a location:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftk0edolrd834isibt1ri.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftk0edolrd834isibt1ri.gif" alt=" " width="200" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rotate &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhngwnt6s3u6t8nioouxm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhngwnt6s3u6t8nioouxm.gif" alt=" " width="200" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Implementation of the rotation move is pretty straightforward:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F90fswf304gb7yola12de.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F90fswf304gb7yola12de.png" alt=" " width="700" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;follow the path &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsdwofpy3yl4o15s7p8zb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsdwofpy3yl4o15s7p8zb.gif" alt=" " width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Implementation is slightly more complicated:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F69x0nc5pc1r24a12gvzg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F69x0nc5pc1r24a12gvzg.png" alt=" " width="761" height="693"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can notice a pattern that in order to create new animation you only have to implement a function and describe how the view (state) changes with time:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27irbdjsyxs1kzjlyw1m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27irbdjsyxs1kzjlyw1m.png" alt=" " width="332" height="54"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Calling such animations in Elmish requires returning it as a Cmd of effect: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feq57j7p7v2yewvshy3rd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feq57j7p7v2yewvshy3rd.png" alt=" " width="800" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Other interesting animations can come from the keyboard events: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm4x2zxaap6qiz3af4rtt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm4x2zxaap6qiz3af4rtt.png" alt=" " width="657" height="50"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check the implementation if you are interested in how I played to emulate a drone flight. Make note that it is a very naive and not complete approach. Actually, this is not the way it should be done: instead, some sort of DeckGL view should be created. However, I had fun with it and could completely control the animation.&lt;/p&gt;

&lt;p&gt;Few more suggestions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;to get the user location (from the browser):&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frwnw35x519pcoa3m23l7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frwnw35x519pcoa3m23l7.png" alt=" " width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;to measure distances and convert between our parameters I'm using &lt;a href="https://turfjs.org/" rel="noopener noreferrer"&gt;TurfJS&lt;/a&gt;, for which binding is even more trivial:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4e3puj0228f2tzxqx82p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4e3puj0228f2tzxqx82p.png" alt=" " width="800" height="184"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt;&lt;br&gt;
This is a brief description of my 3D tiles endeavor. We can go pretty far with it. If you are interested in moving it further or using it in your project, please reach out to me via &lt;a href="https://twitter.com/florence_dev" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>fsharp</category>
      <category>fable</category>
    </item>
    <item>
      <title>Distance Type Provider</title>
      <dc:creator>Paweł Stadnicki</dc:creator>
      <pubDate>Fri, 23 Dec 2022 22:50:34 +0000</pubDate>
      <link>https://forem.com/pstadnicki/data-literacy-with-distance-type-provider-5p9</link>
      <guid>https://forem.com/pstadnicki/data-literacy-with-distance-type-provider-5p9</guid>
      <description>&lt;p&gt;I'm presenting my Distance Type Provider: a little bit different, literacy-close type provider, created for interactive, notebook-driven geospatial explorations. &lt;/p&gt;

&lt;p&gt;If you threaten the geospatial domain as far from your interest, I encourage you to read the post even more, as I'm using tangible, life inspired examples.&lt;/p&gt;

&lt;p&gt;Distance Type Provider plays a crucial role in my other, not yet released endeavor Florence, but can be used alone.&lt;/p&gt;

&lt;p&gt;In short, DTP helps to find distances and travel times for different movement profiles just by typing: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj85jl36knzpebhulaxjf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj85jl36knzpebhulaxjf.png" alt=" " width="800" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find some of the examples I present &lt;a href="https://github.com/PawelStadnicki/Distance-Type-Provider/tree/main/notebooks" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type Providers
&lt;/h2&gt;

&lt;p&gt;Type Providers have many applications and are a fabulous concept on their own. Almost any F# developer had intrinsic desire to create one at some point!  &lt;/p&gt;

&lt;p&gt;They are especially useful in data explorations: you get a local or remote data source and query it.&lt;/p&gt;

&lt;p&gt;Most of the existing type providers have a generic purpose to traverse through well established schemas: &lt;a href="https://fsprojects.github.io/FSharp.Data/library/JsonProvider.html" rel="noopener noreferrer"&gt;json&lt;/a&gt;, &lt;a href="https://fsprojects.github.io/SwaggerProvider/#/" rel="noopener noreferrer"&gt;swagger&lt;/a&gt;. Other serve DSL purpose like &lt;a href="http://fsprojects.github.io/FSharp.Text.RegexProvider/" rel="noopener noreferrer"&gt;Regex&lt;/a&gt;. &lt;a href="https://fsprojects.github.io/FSharp.Data/library/WorldBank.html" rel="noopener noreferrer"&gt;World Bank&lt;/a&gt; type provider is instead one that is very close to the literate programming. It collects development indicators and other data about countries in the world:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgo06oc5cj3lbjygiqh5k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgo06oc5cj3lbjygiqh5k.png" alt=" " width="800" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Literate programming is about writing code, that is meant to be clear to a human being, not a developer itself. In data explorations, any burden distracts and we should document what we already know. &lt;strong&gt;Literate code communicates data as information&lt;/strong&gt;. It is very useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Distance Type Provider
&lt;/h2&gt;

&lt;p&gt;If you follow me on Twitter, you know that I'm interested in smart city and open data domains. They in turn are strictly connected with geospatial, and geospatial is all about distances.&lt;/p&gt;

&lt;p&gt;You may ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Wait! Distance is something you measure, it is a value or variable but not a type! Ok, it can be int or float (or unit of measure) but it already exists...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is all about data literacy. The goal is to not only provide a distance itself, but &lt;strong&gt;ask about it in plain English&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let's start with an example, which describes our life without such a provider. &lt;/p&gt;

&lt;h2&gt;
  
  
  Ordinary code
&lt;/h2&gt;

&lt;p&gt;Assuming we have a set of places (with names and positions):&lt;br&gt;
how can we calculate distances between some wanted places ?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwowehxbhuwr9wgluxd4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwowehxbhuwr9wgluxd4.png" alt=" " width="800" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every developer wrote similar code hundreds of times and it is very easy to follow, even for newbies and people outside IT.&lt;br&gt;
However, we need to filter out wanted entities first. If we want to compare many of them, the code will consist mostly of middle steps everyone has to read (and potentially, likely be distracted from the program goal). Also, with more and more data, data discoverability shrinks.&lt;/p&gt;

&lt;p&gt;So how we could write code with data literacy?&lt;br&gt;
In other words, how we would transform the previous code to a question in English ?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkuil43mwhgbuyhncnpbm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkuil43mwhgbuyhncnpbm.png" alt=" " width="800" height="95"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Distance Type Provider you can write code exactly like above. &lt;/p&gt;

&lt;h2&gt;
  
  
  Geojson everywhere
&lt;/h2&gt;

&lt;p&gt;To make the provider as generic as possible, it expects a geosjon as an input.&lt;br&gt;
If we look at F1 dataset, that contains F1 tracks, we can find some properties that determine these tracks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkko84a7i0junpwvqpkxa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkko84a7i0junpwvqpkxa.png" alt=" " width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The default geojson property that provider expects is "name", so if we run provider without additional parameters, we can check distances based on track names:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgrqq2f4f37kh96dq4nq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgrqq2f4f37kh96dq4nq.png" alt=" " width="568" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we want to use other attribute name, we should pass it as a static parameter:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3j9qu5tf2gkkx2i07tj5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3j9qu5tf2gkkx2i07tj5.png" alt=" " width="767" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What about two different data sources ?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg5ptir8py2qrpdo2dvqk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg5ptir8py2qrpdo2dvqk.png" alt=" " width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MyLife&lt;/strong&gt; geojson is very interesting, as you can define it once and use it in many municipal  analyses.&lt;/p&gt;

&lt;p&gt;Florence even comes with special editor based on Mapbox autofill that you can use directly from the notebooks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdqkvkd8sxyhjxafw96q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdqkvkd8sxyhjxafw96q.png" alt=" " width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
 and/or continue data analyses in the very next cell:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd2o9yfbqhzr04qdcvqsf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd2o9yfbqhzr04qdcvqsf.png" alt=" " width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With such a life space data ready for our disposal, we can rank city places with life-inspired function:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd5ntgkcnptkka3el89ni.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd5ntgkcnptkka3el89ni.png" alt=" " width="765" height="849"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Spatial distance vs actual distance
&lt;/h2&gt;

&lt;p&gt;The easiest way to measure the distance between 2 points is to provide spatial distance, a straight line length. It can be calculated with this &lt;a href="http://www.fssnip.net/7P8/title/Calculate-distance-between-two-GPS-latitudelongitude-points" rel="noopener noreferrer"&gt;formula&lt;/a&gt;. Although it is not 100% accurate for larger distances (&lt;br&gt;
due to possible differences in height above sea level and the fact that the Earth is not perfectly round ) it is fair enough for most analysis.&lt;/p&gt;

&lt;p&gt;So spatial distance is the default one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwyjxced4d4nakpbsv9h9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwyjxced4d4nakpbsv9h9.png" alt=" " width="800" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But there are situations when we need a distance between 2 or more points, that is measured through the exact road or path. Moreover, the road will be different depending on the means of transport used: car, bike, bus. We can always decide to just walk.&lt;/p&gt;

&lt;p&gt;And all of these can return different values on different hours due to the current traffic level.&lt;/p&gt;

&lt;p&gt;Fortunately, there are data providers that do that for almost any area in the World. &lt;/p&gt;

&lt;p&gt;Distance Type Provider leverages Mapbox for this purpose.&lt;br&gt;
Despite the fact Mapbox offers generous free plans, the provider user must use his own token.&lt;/p&gt;

&lt;p&gt;In return you get 3 new profiles: driving, cycling and walking:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj8iplpw92819l7box51e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj8iplpw92819l7box51e.png" alt=" " width="682" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxvtmxcx3p6fhzskvqw0g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxvtmxcx3p6fhzskvqw0g.png" alt=" " width="755" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is nice! What about checking more data at once? Not a problem at all, you can use any place from the geojson combined with any other, even at hoc location:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0sgkg857lso7clc8lfz3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0sgkg857lso7clc8lfz3.png" alt=" " width="800" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just in case you haven't noticed it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpo64sbtxuwe5og6rsb85.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpo64sbtxuwe5og6rsb85.png" alt=" " width="546" height="109"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mapbox direction-matrix API return also expected duration of the travel. That is a nice bonus!&lt;/p&gt;

&lt;h2&gt;
  
  
  What next
&lt;/h2&gt;

&lt;p&gt;To be honest, I added the Mapbox support just 2 days ago so it is all very fresh. The provider itself is still experimental but will evolve ratehr rapidly, / I definately want to add many more capabilities of the Mapbox API.&lt;/p&gt;

&lt;p&gt;I hope it will serve some purpose outside of my own experiments!&lt;br&gt;
Stay tuned for more geospatial stuff related to F#.&lt;/p&gt;

</description>
      <category>fsharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Geospatial is a function of your life</title>
      <dc:creator>Paweł Stadnicki</dc:creator>
      <pubDate>Tue, 06 Dec 2022 10:40:38 +0000</pubDate>
      <link>https://forem.com/pstadnicki/geospatial-is-a-function-of-your-life-1924</link>
      <guid>https://forem.com/pstadnicki/geospatial-is-a-function-of-your-life-1924</guid>
      <description>&lt;p&gt;In this post I present &lt;strong&gt;Florence&lt;/strong&gt;, &lt;br&gt;
a low-code geospatial library for everyone that ranks city places with (life-inspired) functions.&lt;/p&gt;

&lt;p&gt;Florence heavily laverages &lt;a href="https://github.com/dotnet/interactive" rel="noopener noreferrer"&gt;.NET Interactive/Polyglot Notebooks&lt;/a&gt; runtime to hide and execute code behind the scene (including breaking some language constraints).&lt;/p&gt;

&lt;p&gt;I use open data for Zurich from &lt;a href="https://data.stadt-zuerich.ch/" rel="noopener noreferrer"&gt;https://data.stadt-zuerich.ch/&lt;/a&gt;, but you can use any geojson data, including &lt;a href="https://twitter.com/PlaceSharper/status/1585995193035071489" rel="noopener noreferrer"&gt;imaginary Worlds&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Florence is still an experimental library, alpha release is due 24th Dec.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is geospatial hard and boring?
&lt;/h2&gt;

&lt;p&gt;Geospatial isn't hard, it is rather &lt;strong&gt;not accessible for a novice&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You may think that certain tools are expensive, reserved for municipal departments, and that advanced programming is required (in languages you don't necessarily like). &lt;/p&gt;

&lt;p&gt;You can also treat this domain as (a little bit) boring.&lt;/p&gt;

&lt;p&gt;Geospatial might be hard and boring &lt;br&gt;
...&lt;strong&gt;unless you are not aware that you are doing geospatial&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Surprisingly a lot of geospatial analysis boils down to the question "what is the best place for/to ... (anything)?". &lt;/p&gt;

&lt;p&gt;Also surprisingly to answer this very generic question, we can write a very simple function!&lt;/p&gt;

&lt;p&gt;A function that takes place (or facility) and returns its value.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7brto0rf8iab4w36g9b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7brto0rf8iab4w36g9b.png" alt=" " width="800" height="98"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Such a function can be run against all well-known city districts, blocks, or custom areas.&lt;/p&gt;

&lt;p&gt;How to get this data? "You said your library is for everyone but I don't have data-related digital skills...".&lt;/p&gt;

&lt;p&gt;Correct, with Florence you don't care about data retrieval and types, you have it on hand. Just think about having fun(ction).&lt;/p&gt;

&lt;h2&gt;
  
  
  Florence: take a quick look
&lt;/h2&gt;

&lt;p&gt;Florence requires at least one data file to be located in a geojson folder of your &lt;em&gt;VS Code&lt;/em&gt; workspace. Once you load the Florence package, your files are &lt;em&gt;loaded&lt;/em&gt; and you have strongly-type access. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsolrbdfn1r0vi4jpeoqa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsolrbdfn1r0vi4jpeoqa.png" alt=" " width="800" height="689"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notebook's author can share all geojson files along with the notebook. However I created a special &lt;em&gt;geojson.cloud&lt;/em&gt;, so you can explore and download necessary files directly from the F# cell:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl5ocsue0z179k9279ol0.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl5ocsue0z179k9279ol0.gif" alt=" " width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
Under the cover it is some sort of a simplified &lt;a href="https://fsprojects.github.io/AzureStorageTypeProvider/" rel="noopener noreferrer"&gt;Azure Storage Type Provider&lt;/a&gt; but with a capability to share cloud data without sharing the cloud access keys.&lt;/p&gt;

&lt;p&gt;It is very handy, discoverable, and useful especially for bigger datasets, like addresses. Every dataset has necessary license data on folder or file level:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4n1w04tz0zk3yqpn2bln.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4n1w04tz0zk3yqpn2bln.png" alt=" " width="800" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The function of your life&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To do your analysis, you need to write just one function, like the function of your life. Such an activity is not just for fun, it can have many real applications. Imagine all residents are able to write it among plain data querying and joining: we can get exhaustive, the most powerful municipal platform possible. &lt;/p&gt;

&lt;p&gt;As everything that Florence expects is a geojson, your life also must be defined in geojson file. Don't be scared, there will be a nice, graphical way to define your life space directly in the notebook:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8lg35kmufigxkw9q2kz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8lg35kmufigxkw9q2kz.gif" alt=" " width="1093" height="794"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;For the time being, as most of us do not live in Zurich, we can ... rand our lifespace.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnl03qaog50rsr93egmrh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnl03qaog50rsr93egmrh.png" alt=" " width="800" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the cell is executed, quite a lot of magic happens under the cover. You put names of all your important places in a list, their locations are randed, and the special type called MyCityLife is created. When you feed the type with some location, you will get distances to your important places via their names.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7iiqxq8kpf9nvane7mqs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7iiqxq8kpf9nvane7mqs.png" alt=" " width="800" height="331"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The clue here is that those places can be anything, any citizen can name it differently.&lt;/p&gt;

&lt;p&gt;Having your city life space type on your disposal, you can write the proper analytical function:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1lq3afc9d9e9koq2b9l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1lq3afc9d9e9koq2b9l.png" alt=" " width="800" height="117"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This function will be different for many people, even for the same person it can change overtime (there are times when we don't necessarily need our parents-in-law to be close, but it will dramatically change when children arrive).&lt;/p&gt;

&lt;p&gt;You can run your function against the same or any other geospatial file containing city places:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftq0ev0x9vxm7bg624pxp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftq0ev0x9vxm7bg624pxp.png" alt=" " width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distance Type Provider&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;MyCityType used in the calculation is in fact a type created by a special F# Type Provider. It gets all geojson feature's properties and calculates the spatial distance to another provided location.&lt;/p&gt;

&lt;p&gt;There are more applications for this than the presented function of life. You can get the distance between certain places similarly to asking plain questions (example for F1 fans, all you need is a single geojson with F1 tracks):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjmxib3v1uc6kp3oztf5z.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjmxib3v1uc6kp3oztf5z.gif" alt=" " width="998" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also measure a trip:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs4sp5s3w3z94wozfqms4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs4sp5s3w3z94wozfqms4.png" alt=" " width="800" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Other applications&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this post, I did focus on applying the function of life for geospatial purposes. &lt;br&gt;
But this is only the tip of the iceberg of what you can do with Florence. The main capability is to include more data in the calculation. What if the best place should be determined based on route count of the 3 nearest stations ?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27xu3rgk18gr0sy37sj8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27xu3rgk18gr0sy37sj8.png" alt=" " width="800" height="648"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The tricky part is to join datasets in a readable, succinct  manner. You can use the full F# power here. I'm pretty sure F# developers will have fun with it.&lt;/p&gt;

</description>
      <category>fsharp</category>
      <category>polyglotnotebooks</category>
      <category>opendata</category>
    </item>
    <item>
      <title>Pulumi and .NET Interactive (I)</title>
      <dc:creator>Paweł Stadnicki</dc:creator>
      <pubDate>Tue, 13 Sep 2022 14:06:00 +0000</pubDate>
      <link>https://forem.com/pstadnicki/pulumi-and-net-interactive-i-5epm</link>
      <guid>https://forem.com/pstadnicki/pulumi-and-net-interactive-i-5epm</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fba67um1upa05xf1l7xyc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fba67um1upa05xf1l7xyc.png" alt=" " width="800" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this post, I will explain how to provision &lt;strong&gt;&lt;em&gt;Azure Static WebApp&lt;/em&gt;&lt;/strong&gt; with .NET Interactive (Visual Studio Code) and Pulumi Automation API. &lt;/p&gt;

&lt;p&gt;In the follow-up post, I will extend the notebook to cover frequent web app dependencies like API app function, custom domains, etc.&lt;/p&gt;

&lt;p&gt;I'm using the React &lt;em&gt;preset&lt;/em&gt; (with plain &lt;em&gt;dist&lt;/em&gt;), but you can easily adjust the notebook to other static websites build flavors.&lt;/p&gt;

&lt;p&gt;You can download the full notebook &lt;a href="https://fsharptours.blob.core.windows.net/notebooks/post.zip" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To run the notebook you need to have a basic knowledge of Pulumi  (CLI must be installed and Pulumi Access Token set)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;About IaC&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Learning Infrastructure as a Code (Pulumi, Terraform, Bicep, Arm templates,...) is an investment. &lt;/p&gt;

&lt;p&gt;As with any code, &lt;strong&gt;IaC&lt;/strong&gt; is a liability that we must maintain. Also, the underlying architecture must be clear for each team member who touches it. The decision to use it is not an easy tradeoff.&lt;/p&gt;

&lt;p&gt;Often we deploy to the cloud only pretty simple resources. It could be significantly easier to create them via portal and just ... forget. We can think about potential growth and security aspects when it happens. It is all good.&lt;/p&gt;

&lt;p&gt;However, IaC is not only about automation (speed &amp;amp; robustness). It is about disaster recovery too. Let's first talk about the subject we do cover.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Azure Static Web App&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Azure Static WebApp is one of the best options in regards to cost and involved operations to host a web application. It also leverages DevOps well by supporting GitHub actions. &lt;/p&gt;

&lt;p&gt;It means that by creating a resource we also seamlessly run a  workflow to deploy the code from the repository in one shot.&lt;/p&gt;

&lt;p&gt;It is a fast process and doing it via portal requires just a few fields:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl7ddkjci6f3fvs61c1ac.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl7ddkjci6f3fvs61c1ac.png" alt=" " width="800" height="857"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course, to get a more grained set up you have to add proper settings after the provisioning (custom domain, API,...)&lt;/p&gt;

&lt;p&gt;So unless our web app is not a part of a wider solution, using the IaC may be overkill for those who need to learn it first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automation Provisioning = Disaster Recovery&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately despite all of these static web app benefits, I do often encounter troubles with github actions after the initial application deployment. I'm getting completely unclear messages and in order to apply new code changes (which may be critical) I have to reprovision this Azure resource. &lt;/p&gt;

&lt;p&gt;It is not as easy as it sounds when web app is connected to API or uses networking. Deleting all dependencies may be a burden, especially if we want to keep the same namings.&lt;/p&gt;

&lt;p&gt;In such situations, I would like to recreate it by running a program/notebook with a language I know well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;.NET Interactive &amp;amp; Pulumi Automation API&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With .NET Interactive we can run C# (F#, Powershell, Kusto, SQL) from the notebook which makes the process nice, clean and composable with other actions that we can do earlie or later.&lt;/p&gt;

&lt;p&gt;Obviously, Pulumi does not come with .NET Interactive, however to use it we only need to load some nuget packages&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0kze7iwj2ikuth0pkiaa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0kze7iwj2ikuth0pkiaa.png" alt=" " width="800" height="156"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While working with Pulumi (or Terraform), I tend to write a code as I would have had many subscriptions in place for each environment (even if I only have one subscription and I start with one environment). It always pays me off later.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxrwixm9wm044b4t14112.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxrwixm9wm044b4t14112.png" alt=" " width="800" height="172"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pulumi enables (at least) two ways to name the resources&lt;br&gt;
1) Automated&lt;br&gt;
2) Manual&lt;/p&gt;

&lt;p&gt;The first one helps with name conflicts, soft-deletion, zero-downtime deployments (to name a few) but as a side effect produces enigmatic names. It is not always only a personal decision to select proper naming (can be enforced by Enterprise Architectures or so on) however I tend to use the second option.&lt;/p&gt;

&lt;p&gt;In order to use it clearly, all my namings are built up similar to:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc6snpahpnqpbl5r5pxya.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc6snpahpnqpbl5r5pxya.png" alt=" " width="800" height="145"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Flaging environment (dev/qa/stage/demo/whatever) can also impact the resources inputs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7k4nd3d1sf2g48vopkw2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7k4nd3d1sf2g48vopkw2.png" alt=" " width="800" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For Static WebApp we need GitHub credentials which can be kept in a notebook or workspace, depending on where you keep/store the notebook etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyz47jp18xiveu8jobde2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyz47jp18xiveu8jobde2.png" alt=" " width="800" height="117"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that GitHub token should has right to operate on Github workflows&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdvczwmw74uafum3vk8xu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdvczwmw74uafum3vk8xu.png" alt=" " width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You also need to configure Pulumi Automation API. It needs some information as it would have been a standard project:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvug6h25plxanm6i7ftks.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvug6h25plxanm6i7ftks.png" alt=" " width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now it is finally a time for the main dish. &lt;br&gt;
Lets configure Pulumi to create Web App per our needs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7nl3dmqbq4zzdg329xg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7nl3dmqbq4zzdg329xg.png" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lets run the program:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fof54jucc17gq16ptvwyt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fof54jucc17gq16ptvwyt.png" alt=" " width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In case you were only playing around , you can delete the resource by:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F50ne54tvf3xpycfkai14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F50ne54tvf3xpycfkai14.png" alt=" " width="800" height="67"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After reading this post you may consider using .NET Interactive &amp;amp; Pulumi API for your ad-hoc provisioning needs or to enable users of your (open source) project to create needed infrastructure and host a copy of the product.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>pulumi</category>
      <category>dotnet</category>
      <category>iac</category>
    </item>
    <item>
      <title>Processing Open Street Map data with F# and .NET Interactive</title>
      <dc:creator>Paweł Stadnicki</dc:creator>
      <pubDate>Mon, 22 Aug 2022 21:17:00 +0000</pubDate>
      <link>https://forem.com/pstadnicki/processing-open-street-map-data-with-f-and-net-interactive-4lh6</link>
      <guid>https://forem.com/pstadnicki/processing-open-street-map-data-with-f-and-net-interactive-4lh6</guid>
      <description>&lt;p&gt;There are several reasons you may want to obtain municipal data.&lt;/p&gt;

&lt;p&gt;You can present them nicely on your website in a form of an interactive map, or you can perform some geospatial analysis like finding distances to the closest facilities.&lt;/p&gt;

&lt;p&gt;Or maybe you just want to play with F# language on real, tangible datasets?&lt;/p&gt;

&lt;p&gt;In this post, I explain how to get any data from &lt;a href="https://www.openstreetmap.org/" rel="noopener noreferrer"&gt;OpenStreetMap&lt;/a&gt;, convert it to geojson, and parse for wanted places so you can take them and have further adventures with F# and real data.&lt;/p&gt;

&lt;p&gt;You can download the notebook &lt;a href="https://fsharptours.blob.core.windows.net/notebooks/London.zip" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;*You still have to generate geojson file on your own as described in the post&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open Street Map / Open City Data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;OpenStreetMap is an excellent source of city data that is absent or not covered enough by the open data portal maintained by city governors.&lt;br&gt;
This is especially useful for small cities and villages (that don't have data portal at all) or to quickly get data that have potential commercial value.&lt;/p&gt;

&lt;p&gt;Be aware, that in contradiction to open city data, OSM data are not complete and hence not perfect for many business scenarios. The data are most often injected by plain users, which puts the OSM data schema robustness ...at risk.&lt;/p&gt;

&lt;p&gt;Even if you are among lucky citizens where the data portal shines (please check ~200 geojson files for Rostock (Germany): &lt;a href="https://www.opendata-hro.de/dataset/?res_format=GeoJSON" rel="noopener noreferrer"&gt;https://www.opendata-hro.de/dataset/?res_format=GeoJSON&lt;/a&gt;) you can still find OSM valuable and complementary to aforementioned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm using data for London, as it is a huge city that still lacks some publicly available open data. Also, the data volume itself requires special steps not needed for smaller areas. I parse rivers, addresses, shops, and leisure; however, any facility for any city can be obtained in the same (or almost the same) manner.&lt;/p&gt;

&lt;p&gt;What I do present here is zero rocket science, just grabbing data, converting to geojson, and parsing. I'm sharing it as &lt;strong&gt;it can be tedious for someone who never worked with geojson in C#/F#&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Yes, you can write an &lt;em&gt;idiomatic functional parser&lt;/em&gt;, "type provider" as well, however, I'm not sure it will make working with these data more pleasant and approachable to the average programmer (taking into account OSM data schema flaws)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Getting data from Open Street Map&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Python&lt;/strong&gt;ists have plenty of OSM (and all relevant geospatial) libraries at their disposal, there are some libraries for dotnet as well.&lt;/p&gt;

&lt;p&gt;However, I like to work primarily with &lt;em&gt;raw geojson files&lt;/em&gt; as it is a well-known, human-readable format so I can go through the file to understand how to process the wanted data.&lt;/p&gt;

&lt;p&gt;Go to &lt;a href="//openstreetmap.org"&gt;OSM&lt;/a&gt;&lt;br&gt;
and you will see some map tiles:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzxabvcsriyfhq0nz8jce.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzxabvcsriyfhq0nz8jce.png" alt=" " width="800" height="621"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You have at least two options to select the city that is relevant to you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;scroll accordingly to cover the wanted area and press export -&amp;gt; overpass API
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fot8vusiohgvjj0w09cj5.png" alt=" " width="800" height="527"&gt;
&lt;/li&gt;
&lt;li&gt;or type wanted area name and then click 'export'.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Be aware that these options have limitations in size, you cannot download too large areas this way. For example, I'm not able to download the whole London data. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86gud2hb7o3xzym6mb2f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86gud2hb7o3xzym6mb2f.png" alt=" " width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In such scenarios, you can download the appropriate datasets via plenty of pre-generated files. For London you can find it here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://download.geofabrik.de/europe/great-britain/england/greater-london.html" rel="noopener noreferrer"&gt;https://download.geofabrik.de/europe/great-britain/england/greater-london.html&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwi2646k0uvmts9vw9psv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwi2646k0uvmts9vw9psv.png" alt=" " width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Converting to geojson&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After download, we have ~1.5 GB OSM file&lt;br&gt;
To convert it to geojson I'm using npm package called ... osmtogeojson. For those who are not working with nodejs on a daily basis it is very simple: just install the tool globally&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tyrasd/osmtogeojson" rel="noopener noreferrer"&gt;https://github.com/tyrasd/osmtogeojson&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flr3m5hs6g8peg3gvqt43.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flr3m5hs6g8peg3gvqt43.png" alt=" " width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
and then convert &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1w3602a5pxy0gi6bq2v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1w3602a5pxy0gi6bq2v.png" alt=" " width="617" height="153"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbd6k2ljow4fqgwbvynm1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbd6k2ljow4fqgwbvynm1.png" alt=" " width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For London file I'm getting out of memory error hence need to run the program, based on the clue from the documentation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvd4pzq4m4slick8tavcg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvd4pzq4m4slick8tavcg.png" alt=" " width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdmy6h7eqi2jqc9lk15l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdmy6h7eqi2jqc9lk15l.png" alt=" " width="800" height="22"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The conversion takes ~1-2 minutes for such large file. &lt;br&gt;
For smaller cities it can be simpler to download data in *.shp format and convert to geojson via mapsharper.com, &lt;a href="https://mygeodata.cloud/" rel="noopener noreferrer"&gt;https://mygeodata.cloud/&lt;/a&gt;, ArcGis or many, many other options.&lt;/p&gt;

&lt;p&gt;As we have a file, we need something to process it.&lt;br&gt;
In my case, it is .NET Interactive extension for Visual Studio Code. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;.NET Interactive&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can now open downloaded notebook in Visual Studio Code. &lt;br&gt;
The notebook (*.dib) I provide for you expect the geojson file to be in same place (otherwise please adjust the path accordingly).&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmqnrrdvjm8mndy38fzmu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmqnrrdvjm8mndy38fzmu.png" alt=" " width="800" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The very fist notebook cell loads geojson file and parse it to get the items. There are almost 2mln of items processed in 6 seconds. Not that bad. &lt;/p&gt;

&lt;p&gt;Now get some city goodies, starting with ...water.&lt;br&gt;
But only rivers that have some name assigned.&lt;/p&gt;

&lt;p&gt;This ...TryGetProperty.. from JSON deserializer is not perfect here, definately could be wrapped somehow but I just want here to show how things work without DSL.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F26hhe6k48q2gdkf4tmvg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F26hhe6k48q2gdkf4tmvg.png" alt=" " width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Output of the code depends on extension you have installed. Unless you have some renderer extension from marketplace you will see just raw text. &lt;br&gt;
My favorite one is the Unfolded Map Renderer extension created by Taras Novak, however it has been made private recently (unless you are supporter as I'm). You can still use one of his many other extensions available here:&lt;br&gt;
&lt;a href="https://marketplace.visualstudio.com/publishers/RandomFractalsInc" rel="noopener noreferrer"&gt;https://marketplace.visualstudio.com/publishers/RandomFractalsInc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to store the result of your filter in a separate geojson file, you  can do it by &lt;br&gt;
:&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfc2g0uvofellpwqatpa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfc2g0uvofellpwqatpa.png" alt=" " width="800" height="113"&gt;&lt;/a&gt;&lt;br&gt;
and host on your website, open and play with any other tool like geojson.io&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnyg76wav1qsoe2fkzu9n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnyg76wav1qsoe2fkzu9n.png" alt=" " width="800" height="642"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can query whatever facility you want:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1eeu5lohisx0o4icvns0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1eeu5lohisx0o4icvns0.png" alt=" " width="800" height="497"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;... using as many functions from collection modules as you want&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F32kn48cpfwnt1vvh6let.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F32kn48cpfwnt1vvh6let.png" alt=" " width="800" height="687"&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Random addresses&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What about addresses ? Well, I rarely need to process them this way as typically municpal portals enables them or they are available via &lt;a href="https://batch.openaddresses.io/data" rel="noopener noreferrer"&gt;Open Addresses&lt;/a&gt;. Apparently London does neither of them ( I believe this is because of a private sector etc).&lt;/p&gt;

&lt;p&gt;Addresses in OSM are (from my best knowledge) NOT a standalone object, it means they are just attributes of associated objects.&lt;br&gt;
It can end up with many objects having the same address, and what is more important: they can be either points of polygons. And we most likely want to have unified shapes like point.&lt;/p&gt;

&lt;p&gt;First, let get them with a familiar approach that additionally does some distinctions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3p4msfgwm4gv4x38fc5f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3p4msfgwm4gv4x38fc5f.png" alt=" " width="800" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Is this 113k addresses a correct number of real addresses ? I don't think soo but it still is usefull dataset for experiments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using NetTopologySuite for geospatial analysis&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We already did a lot, but in order to do more we have to introduce dedicated library/package. In dotnet it is &lt;a href="https://github.com/NetTopologySuite/NetTopologySuite" rel="noopener noreferrer"&gt;NetTopologySuite&lt;/a&gt;.&lt;br&gt;
You can achieve a lot from the geospatial perspective with this library, here we just want to get centroids for polygons. Additionally I'm getting rid of unwanted properties, keeping only street, number and city.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fecdkze8xvrxjewbz98je.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fecdkze8xvrxjewbz98je.png" alt=" " width="800" height="716"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Important remark!&lt;br&gt;
NetTopologySuite doesn't work nicely with .NET Interactive, it will hang forever unless you are using old interactive version.&lt;br&gt;
So if you want to run the rest of cells&lt;br&gt;
you have to temporary rollback to mentioned version:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn5jez54i2wsjhsm12doi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn5jez54i2wsjhsm12doi.png" alt=" " width="471" height="406"&gt;&lt;/a&gt;&lt;br&gt;
There is a workaround suggested from .NET Interactive team to make it work with latest version, I will update the post as soon as I know how to apply it.&lt;/p&gt;

&lt;p&gt;We started to process data with System.Text.Json. &lt;br&gt;
NetTopologySuite has equivalent version for processing geojson called NetTopologySuite.IO.GeoJSON4STJ. However here I'm using the regular one as "STJ" doesn't work properly with my advanced processing (not covered here). Hopefully all at some point will be unified.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Lets rand some addresses. *&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mbuio98om4319865tg3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mbuio98om4319865tg3.png" alt=" " width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please note than when using projection library build on WebGL (like unfolded), displaying hundreds-of-thousands items is very smooth&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe1y8e1lzq6hz8qg08dlb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe1y8e1lzq6hz8qg08dlb.png" alt=" " width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What next&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I presented how to obtain and process geojson municipal data.&lt;br&gt;
Actually it should be called "preprocess" as I haven't touch any interesting processing from the user perspective. Now we could connect this with actual "domain" processing, join with other data sources and add true F# expressiveness on top of that.&lt;br&gt;
But this is for another story.  &lt;/p&gt;

</description>
      <category>fsharp</category>
      <category>dotnet</category>
      <category>osm</category>
    </item>
  </channel>
</rss>
