1. 49

  2. 17

    I’m planning to post an introduction to the type system/tutorial on how to read the type signatures of Ur/Web on monday or so, so I’m posting this here now in hopes of gathering some interest in the language.

    1. 2

      I’ve been interested for a while but have given up a lot sooner than you have based on the same problems you encountered, which are not insignificant. I’d be glad to read anything you’d like to post about Ur/Web that made it slightly more accessible. Thanks!

    2. 9

      In case people are looking for more, I wrote a post describing (in semi-literate style) a tiny application I made while experimenting with Ur/Web ~6 years ago. I would guess that the Ur/Web code still works (I don’t think the language has changed much), but the browser stuff might not, and I’m not hosting a copy a demo of the application anymore (sorry!).


      1. 7

        I subscribe to BazQux which is an RSS reader that uses Ur/Web and I couldn’t be happier with the service.

        1. 6

          I’m a fan of Ur/Web and would like to see more articles on it. I used it for a couple of production systems and it was great. I still use it for personal projects that use a web UI. The application executable can be compiled statically with musl libc enabling it to run on almost any Linux system. Very useful.

          1. 9

            In the age of languages like Elm and Go, which jeopardize sophistication to appeal to the newcomers,

            I have a bone to pick with this. Go isn’t approachable because it wants to be popular, it’s approachable (a.k.a. simple) because that’s what the designers wanted out of a language they themselves would have to use. The simplicity is a feature. It is also very sophisticated, just a lot of that sophistication is hidden under a single keyword like go.

            1. 10

              The author of the post Notes on structured concurrency, or: Go statement considered harmful argues that the go keyword in golang enables a kind of spaghetti code similar to the goto famously critiqued by Dijkstra in the 60s. I work full time with golang, and in practice folks are conservative with their use of the go keyword, but I tend to agree with Nathaniel about its potential for abuse. The go keyword makes concurrency easy but it doesn’t make it simple. I take the stance that the go keyword is not a mark of sophistication in the golang language.

              [Edit: I realize this is off topic.]

              [Edit again: A more on-topic response follows.]

              In the age of languages like Elm and Go, which jeopardize sophistication to appeal to the newcomers,

              Thinking about it some more, this is kind of a cheap-shot.

              Golang’s sophistication is in its efficient GC, multiple profiling tools, ability to profile at runtime, speedy runtime, fast compile times, and its ease-of-use. @bigdubs has a point. The language was designed to improve development practices at a large company and allocated its sophistication budget to support features which address that goal.

              Elm’s sophistication isn’t reduced by its ultimate farewell to FRP. FRP itself has become a nexus of difficult to differentiate ideas. Having met Evan Czaplicki a couple times and discussed his goals with Elm, it’s clear to me that his desire to help people learn Elm outweighed his desire to make it fit the FRP label. That isn’t a rejection of sophistication.

              As somebody who spends most of their free time in Haskell, I’m familiar with the “sophistication” that doesn’t “appeal to the newcomers”, in @steinuil’s words. It’s a sophistication that sometimes bites me after working with Haskell for several years, and I still question its value while continuing to do new projects with Haskell. This cusp between complex and difficult but sophisticated tools and seemingly simple or easy tools which belie their own sophistication is a difficult point and I don’t think either side of the argument has a winning set of ideas.

              That said, thanks @steinuil for introducing me to Ur/Web. I’d never heard of it. It sounds a bit like yesod, servant, dart, and reform (digestive functors) all rolled into one. I’m looking forward to your next post.

              1. 4

                I admit it was a cheap shot, I probably wouldn’t word it like this today. I did have a lot of problems handling and scaling some medium-sized Elm applications though; nothing in the documentation suggested how to structure big applications in a nice way and even though I can think of some ways to do that now it still involves a lot of boilerplate.

                My animosity towards Go might’ve been more of a knee-jerk reaction; I know it has a lot merits in its tooling but I still disagree with many of the tradeoffs it makes in its design. But I’m sure I’ll have nicer things to say about it if I ever use it for something bigger.

                1. 1

                  Golang’s sophistication is in its efficient GC, multiple profiling tools, ability to profile at runtime, speedy runtime, fast compile times, and its ease-of-use.

                  Only one of those things you listed could possibly apply to the language; the rest are properties of the runtime/ecosystem. I’m not sure if that was the point you were trying to make, but it seems to indicate that the Go language is rather simplistic.

                  1. 2

                    Ah, not exactly. I was attempting to make the point that there’s sophistication in “golang” without distinguishing between the “golang language/syntax/semantics” and the “golang runtime”.

                    Are there other languages which run natively against the golang runtime and are able to leverage its benefits? If not, then for the time being it seems reasonable to regard the benefits (or sophistication) of the runtime as benefits of the language. Those benefits are obtained based on the choice of whether to use the language or not, since you can’t get the runtime without the language at current.

                    Reading a bit about golang’s runtime it seems like a poor name, to be honest. It’s a library runtime. There’s no VM. If you wanted to leverage the benefits of the runtime I suppose you could link against it from another surface-level compiler, but the API is likely unstable. It’s probably easier to write a language which compiles to golang. I still think it’s fine to regard the two as one artifact.

                    1. 4

                      I still think it’s fine to regard the two as one artifact.

                      I guess I feel it’s helpful to consider them separately because it’s clear to me that the golang creators are not very good at language design and have made a significant number of obvious mistakes on that front, pretending that the state of the art in programming language design hasn’t moved forwards since the 1970s, but at the same time they actually seem to do a decent job at tooling, compiler implementation, and non-language-level ergonomics.

                      1. 1

                        Is the go runtime any different than the ada runtime in this regard?

                      2. 2

                        The language was kept simplistic to enable building the runtime features, so it’s relevant if bot precisely correct.

                  2. 4

                    Can anyone compare Ur/Web to Yesod? From this overview, it sounds like they share many of the same goals surrounding safety.

                    1. 7

                      Yesod doesn’t have code that is transparently compiled to client-side (at least not without a lot of GHCjs hackery, which wouldn’t be part of Yesod), any of the transparent reactive stuff (which works smoothly with the client-server stuff), and in general, at least in my experience (which is somewhat limited – I’ve done a lot of Haskell web dev, though only a little with Yesod, and I’ve built a few applications with Ur/Web, but nothing big), things in Yesod are much more first order. i.e., functions in Ur/Web become handlers in a natural way, can be called by client-side code with rpc, etc. Urls exist, of course (and they are not obfuscated), but you won’t really be using them (even as typed constants like with Yesod) unless interacting from outside the application. And in general everything feels like it is at a much higher level of abstraction, vs. Yesod has the express goal (AFAIU) to essentially make Rails-style web development type safe.

                      1. 2

                        Most of that makes sense, but what do you mean by “won’t really be using [URLs]”? My Yesod experience is also pretty shallow (got a ~2k LOC app with 13 handlers). In a server rendered form, you’ll have something that looks like: <form method=post action=@{FooR var}>. What looks different in Ur?

                        1. 2

                          Maybe this is just my knowledge being dated (I last experimented with Yesod years ago), but I had thought you had to declare routes to handlers, and use identifiers generated by that process for urls, form actions, etc. Can you just put any function that has the right return type in a url / action? (that’s essentially what Ur/Web lets you do).

                          1. 2

                            I see, and your memory is right, based on my understanding. Sounds like there’s a bit less ceremony. I’ve edited my example for clarity–FooR is what you use, and it would correspond to a postFooR :: Text -> Handler Html function.

                      2. 1

                        Can anyone compare Ur/Web to Yesod?

                        Or Ur/Web to Obelisk (uses reflex).

                      3. 4

                        I think the problem may be a lot simpler: academics are incentivized to crank out papers, not code, at a high quantity. Although some kindly open code, those projects are often more like incomplete, non-polishes prototypes with minimal to no maintenance over time. This is extremely common.

                        Chlipala seems like one of the elite performers in verification field. He’s always on new projects. The state of Ur/Web is probably due to these incentives where he did what he could within his strong areas and time constraints. Since it’s open, people aiming for approachable, well-maintained stack can port some of his ideas with better polish. So, not all a loss even if Ur/Web itself stays in current state.

                        1. 4

                          I found this tutorial for building a simple blog in ur/web quite good a few years back. So much so that I submitted a PR (unfortunately no response in 3+ years) to fix some of the typos and vague things that I struggled with while following along.

                          1. 2

                            i’ve considered ur/web several times, and each time i run into the issue that there isn’t much of a library ecosystem. i currently use js_of_ocaml, so i already have the ML-for-web experience and all the ocaml libraries out there; ur/web looks like it has some advantages over ocaml if i want to write a database-backed client/server app but for apps that live mostly or entirely in the browser ocaml’s ecosystem advantage wins out.

                            1. 2

                              I agree, the lack of an ecosystem and the problems I mentioned in my post usually make me choose other languages/stacks. I’m unsure if it’s a better idea to focus on improving a somewhat more mature ecosystem like OCaml’s than trying to revive Ur/Web’s, but I think it’s worth trying.

                            2. 1

                              Is there an FFI or or some other mechanism to interact with the surrounding JS environment or DOM from Ur/Web on the client side?

                              1. 2

                                Yes, calling external JS functions is pretty effortless, but you should be able to do everything you need in terms of DOM manipulation using the <dyn /> tag.

                                1. 1

                                  Thanks for your answer! I found a few simple examples that shows interaction which simple functions. Do you know of some more elaborate examples of interaction with complex JS libraries and objects? Something like leaflet for example?

                                  1. 1

                                    I don’t know of any examples, but looking at the simple examples in the documentation of Leaflet it looks like it wouldn’t be too hard. For example you would define a map type, bind some functions to add objects like markers and circles, and then define addTo to be a function that takes the item you want to add, the map and returns a transaction unit, since adding an item is an effectful action.

                                    The API seems pretty complex but I think the hardest part would be mapping JS idioms to Ur/Web’s and setting up the types.