This sounds very interesting. You say “native” but miso generates JavaScript, right? I’m not familiar with mobile development. Can you run JS natively on mobile devices?
Yes, miso uses the JS backend in GHC, and mobile phones have embedded JS interpreters (e.g. JavaScript Core). These interpreters can access native libraries to draw native views, or access native device APIs.
Projects like lynx and react-native automate this process using something akin to node-gyp, exposing kotlin / swift libraries via C ABI w/ a JS API. Miso accesses the kotlin / swift native modules by FFI'ing into the JS that exposes them.
The JS doesn't get compiled, but on Android it does get JIT'd. So it's "native" in the sense that the views drawn are native (not WebViews), and the device APIs are native, but not "native" in the sense that it's compiled.
This post dismisses Elm on the basis of lack of typeclasses, but fails to mention miso (https://haskell-miso.org), that includes typeclasses. Miso is Elm-as-an-embedded-DSL written as a Haskell library for GHCJS that allows one to share types on the front and backend, take advantage of the entire Haskell ecosystem and has experienced commercial use.
I agree that Miso deserves a mention. It seems to be very actively maintained.
On the other hand, if you reject GHCJS then Miso is out of the running immediately. And the reason to reject GHCJS (big bundles, as mention in the article) is something you dont have in Elm/PureScript/ReasonML.
There is a company that has a 400 module miso application and the bundle size is not an issue (https://www.polimorphic.com). After closure compilation GZIP'ing, pre-rendering and caching of the JS, it's a one-time cost, and is negligible due to pre-rendering. We build websites for users, who care only about experience, not about how large the payload is. Payload only matters insomuch as it adversely affects user experience. This argument is strictly a developer concern and is in no way correlated with end-user feedback. There are many <1MB js payload size websites with 0 users.
After our bad experience in 2016 using GHCJS on a big project, we haven't considered it for anything since. Anything that arrived after that related to GHCJS just hasn't been on my radar ("a history of my own experience in this problem space").
If decoding json in Elm is considered hard, I'd recommend checking out miso (https://github.com/dmjio/miso), a Haskell re-implementation of the Elm arch. It has access to mature json libraries like aeson for that sort of thing, along with mature lens libraries for updating your model. Here's an example of decoding json with GHC.Generics using typeclasses.
https://github.com/dmjio/miso/blob/master/examples/xhr/Main....
You don't need to switch a whole language because of JSON decoding. There are many tools that exist to aid you write JSON decoders in Elm. The language is not just about the architecture -- you can implement the architecture in any language, as Redux has proven. What people like about Elm is the compiler and design philosophy that radiates through the entire community. Switching to Haskell won't give you that, as the Haskell community has different priorities.
I am kinda waiting for Purescript to mature a tiny bit more in this regard, because it seems that they have something special brewing there, with their polymorphic record type and interesting take on type-level programming.
Because this [1], even though it seems to be just a experiment so far, looks really good.
I.e: doing
type MyTestStrMap =
{ a :: Int
, b :: StrMap Int
}
and then just calling
let result = handleJSON """
{ "a": 1, "b": {"asdf": 1, "c": 2} }
"""
let newResult = doSomething (result:: Either MultipleErrors MyTestStrMap))
is kinda all I ever wanted in these haskell inspired languages?
This is very cool. The example apps are relatively slow to load compared to the equivalent in some other frameworks (my favorite is Mithril for an idea of how small/fast these can get).
Was wondering whether it might be a slow server, but the app.js for the TodoMVC appears to be over a megabyte (1.21 MB, have a 4000 line Mithril app which is 500k uncompressed). What's up with that?
ghcjs is a pretty heavyweight environment. It's actually translating the compiled core IR from GHC into JavaScript, and including a port of GHC's runtime system.
It can run basically any Haskell library. That includes the ability to run multithreaded Haskell code -- the JS RTS includes a scheduler. You also get Software Transactional Memory. Lazy evaluation works just as usual -- and so on.
The tradeoffs become worth it when you have a sufficiently valuable base of Haskell code that you want to run in the browser, and when your users aren't very constrained by page load time. Say, if you have some complicated tricky logic that you don't want to rewrite in another language, but you want to use it in your web app.
Aeson is SLOOW compared to 'JSON.parse' + GHCJS ffi. You lose a bit of correctness (JSON.parse can decode numbers only to the JS precision, ie. 53bits, while Aeson supports arbitrary precision through Scientific), and ability to decode streams in constant memory. But these are features which you most likely don't need in a web app.
There’s no reason to use genericParseJSON here, you can just write “instance FromJSON APIInfo”. Or leave the instance declaration as it is and safely rename your record fields to e.g. currentUserUrl instead of current_user_url.
The purpose of the camelTo function is to convert “camelCaseExample” into e.g. “camel_case_example” by passing ‘_’ as the first argument. But the APIInfo data structure already uses record fields with underscores in them.
Building native applications for iOS, Android and Huawei devices in Haskell.