Hacker Newsnew | past | comments | ask | show | jobs | submit | tejasv's commentslogin

We do. Chaldal (YC S15), see https://chaldal.tech/


We're an F#-first company and I'd like to share our experience here.

All our new code is in F#, we started off from a C# codebase, so that made the transition somewhat manageable, as new F# code can be directly called from C#, and vice versa (still took over 2 years). All new frontend apps are also being written in F# (using Fable), as of 6 months back, migrating away from TypeScript, this forces everyone into a "design your model first, and well" paradigm. We've written quite a bit of code to blur the lines between traditional backend and frontend development roles, so what we have now are:

- product engineers (who write application logic on both frontend and backend to serve business needs)

- platform & framework engineers (who write the underlying persistence/serialization/versioning/frontend-backend-sync websocket/load balancing/IDE extensions/deployment etc)

- component designers who focus on visuals

Platform/framework engineers try to encapsulate as much magic as possible into computation expressions (F#'s monads), so product engineers can focus simply on writing out business intent, with readability given very high priority. We also make ample use of quotations to do some cool tricks (like predict the future states some type can take, based on current state + available transitions).

Our code written in F# has an order of magnitude fewer bugs when it makes it to production, given the amount of thought we pour in modelling the problem domain accurately, and thanks to functional programming itself. They're also more amenable to business requirements changing, simply because they've been modelled well to start with. Nothing that can't be achieved in other languages, but with F#, this happens more naturally.

Almost everyone in our team has learnt F# on the job, and overall, everyone's experience has been extremely positive. There's a bit of difficulty in the first 2-3 months, as junior devs get introduced to functional thinking, but if you've generally being doing functional programming, this is just about learning new syntax, tooling and F#'s choice of operator naming (map/bind/pick/collect/choose/..). Typically, based on prior experience, we ask newcomers to spend two weeks to a month, solving the first 100 problems on Project Euler in F#, without using the mutable keyword, and we assign a mentor to point out best practices and review their code.

The hiring pool for F# devs is much smaller than the regular applicant pool, but if a candidate shows genuine interest in F#, they are usually 10x more likely get through our interview process. If they've discovered F#, it means they find something lacking with mainstream languages, so they're likely to have many years of experience under their belt, and they've found a way to grow. That said, we don't restrict our hiring to simply F# devs.

For more info about us, see chaldal.tech (YC/S15).


Amazing! I’d be interested- the problem I have in the FP space is not getting the F# or Haskell experience so you have to “keep up in your spare time” and with other commitments I have to choose what to keep up with and the rarity of FP jobs means it makes more sense to say learn Redux, Sagas, that kind of stuff etc. So I think it’s good if companies like yours would take pure enthusiasm with proven knowledge of other programming languages and desire to learn F#. But I guess it depends as you may have a queue of people wanting a FP job so you can be choosy!


I find the same thing. Getting the experience can only happen in time I direct. I have scope to use F# at work but still fear that choice is not the best for the company I work for. Yes I will love the tooling and right now I'm there but it won't always be that way. They won't be able to find contractors to make changes in the future. I have to give them solutions they can run with in the future or they will be forever regretting me once I'm gone.


If you're on a .NET stack, F# is a secret sauce; its just not many have bothered to look :) Maybe discuss with your CTO and make a collective decision to invest in it by understanding what it brings to the table, and don't worry too much about the future, like having to hire F# devs. As I described above, guiding existing devs to learn F# is the equivalent of training them to think better (as PG/Eric Raymond quote, it will "make you a better programmer for the rest of your days"). If a small handful of you within the company develop expertise, you can guide others. And what's more; if you do pick up F#, many skills are transferable to other FP jobs (like Scala). There's a leap-of-faith element involved, but it has been paying us dividends.

Also, I really like this post: https://fsharpforfunandprofit.com/posts/low-risk-ways-to-use...


Please can you sure more about this?

> We also make ample use of quotations to do some cool tricks (like predict the future states some type can take, based on current state + available transitions).


Here's is a simplistic example of a state machine:

  let transition (state: State) (action: Action) : State option =
     match (state, action) with
     | (StateA, ActionA) -> Some StateB
     | (StateA, ActionB) -> Some StateC
     | (StateB, ActionA) -> Some StateB
     | _ -> None
If you get the quoted representation of the transition function, it can be visualized as a tree data structure (like code-as-data in LISP). You can analyze that tree to understand that if current state is StateB, only ActionA can be applied on it.

Couple this with another realization: "Any sufficiently complicated model class contains an ad hoc, informally specified, bug-ridden, slow implementation of half of a state machine." (not sure where I read this quote).

This means all the entity framework/ORM crap work that we do can actually be neatly represented as transforms on a F# state machine, which suddenly makes the application more powerful if you give it this structure.

We use this technique to auto-generate admin panels.


> "Any sufficiently complicated model class contains an ad hoc, informally specified, bug-ridden, slow implementation of half of a state machine." (not sure where I read this quote).

Can’t tell you where you read it, of course, but believe it originates from Braithwaite/raganwald:

http://raganwald.com/2018/02/23/forde.html


Do you blog any of this or do any sort of writing on the topic. I think I could learn a lot from the way you are doing things.


Not yet, it has been on my list for a long time. Meanwhile I recommend this blog that collates all good F# content from around the web weekly:

https://sergeytihon.com/category/f-weekly/


Take a look at F#'s type solver code especially wrt to Extension Typing: https://github.com/dotnet/fsharp/blob/main/src/fsharp/Extens...

You can do similar things with other Ocaml or Lispy Langs, depending on how you want to do it. All you need is a function that returns possibleTypeTransitions for givenType(type, enclosedLexeme, type.validTransitions). A gradually typed lang sitting in top of a prototype-based blob also makes this easy to do (see typescript) in-codo.

See also MacKay (RIP)'s classic book: http://www.inference.org.uk/itprnn/book.pdf


How's your experience with Fable, especially when using third party JS libraries?

I'm really having fun experimenting with F# for my API server, but I hesitate to use it on the front end.


That's a good pitch!


Maybe it's my unsophisticated mind talking here, but programming in F# is pure joy.Among the languages I use only Ruby gets close to provide that feeling.


Yes :) That moment when it simply clicks, it's not something that goes away. It has certainly made my day-to-day programming work a lot sweeter, hence I can't shut up talking about it. And it's not like I write some esoteric ML or data science code, a lot of these are boring line-of-business applications, yet it is so satisfying designing those in F#.


Does interop with c# get easier?

Trying to figure out how to map to an overloaded C# callback (maybe hidden in an *.extension doc!) has wasted hours of my time.

F# (the ml family in general) is my favorite language right now but, man, the .net APIs are rough.

Lacking the same UX I’m used to in Node, Ruby, and Elixir.


Interop is janky. It works, but there are some gotchas that need to be worked around. It works in 95% of the cases without much mucking around, but it's not pretty, so you're better off tucking that away in some dark corner.


Can you explain the interop a bit more? I’ve been looking into an F# job. Having a functional background, the language looks nice, but I’m wondering about the ecosystem. Can you not use .Net libraries as easily as you can from C#?


Yes. Typically interop is very straightforward. You look in the api docs and copy paste.

Example here is the String doc[1]. Way down you see all the methods. Some of the methods have overloads (multiple variants). Pretty straightforward here. (E.g. `"mystring".Contains("ring")`)

Where it gets more verbose and finicky is when the API takes a C# callback. Even more complex is if it’s asynchronous so it takes a C# callback as a Task.

An example being the `.Use` method for defining server middleware.[2]

To see how it’s done, here’s a gist I found.[3] Notice how the function for requestHandler is verbosely annotated with Func<> and RequestDelegate, etc.

Luckily this isn’t the norm, most APIs are less complicated. Even so, you write a wrapper (abstraction) around that complexity and only look at your wrapper. Which is why someone in this thread said to leave them in a dark corner.

[1]: https://docs.microsoft.com/en-us/dotnet/api/system.string?vi...

[2]: https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnet...

[3]: https://gist.github.com/kspeakman/7870a75283f6942dd96ff34a03...


I think it will get better in F# 5.1, which adds native C# Task support... https://github.com/fsharp/fslang-design/blob/master/RFCs/FS-...


In the meantime, you can use the fantastic TaskBuilder.fs for C# Task support and interop.

https://www.nuget.org/packages/TaskBuilder.fs/ https://github.com/rspeele/TaskBuilder.fs


Thanks. I appreciate the explanation.


We, at Chaldal (YC S15, chaldal.tech), use F# in production. Most of our backend projects are in F#, the last one is being migrated over slowly from C#. Our new frontend projects are also in F# (using Fable).

I want to share some insights of using F# with the community. We started from a C# codebase, and realized that a better language can help weed out most bugs in our system. And yes, it works. Pretty much all bugs we face these days are parts where the F# world touches something non-F#, like .NET and other libraries written for C#, where interaction (like nulls) is not well-defined. We've taken Scott Wlaschin's (fsharpforfunandprofit.com) teachings to heart, and we have a giant banner in our office that reads "Make illegal states unrepresentable".

It took a bit of learning for everyone to jump in, but our dev team has loved the experience as the language is a pleasure to use; when they need to go back to write C# or TypeScript code, a lot of these learnings transfer. People just become better programmers (as is true with learning any functional language).

To get all the benefits of F#, you must adopt the whole paradigm. While F# allows C#-like OOP, and while this can be an initial stepping stone in the path towards F#, you must go all the way. If you simply do OOP, the trade-offs aren't worth it, IMO, as F# is a functional-first language, and the OOP is mostly provided for interop with the rest of .NET.

IDE support has been janky in the past, but its improving. Latest VS 2019 is pretty good, and JetBrains Rider works pretty well on the Mac.


I get the "Make illegal states unrepresentable" in theory but how do you do it actually for nontrivial preconditions like "this list must be sorted"? (as a precond for a binary search on a vector, for example).

OOP is fine with functional if you make it immutable too, so I don't see the problem (I've not really got a problem with mutable OOP, or state generally, if it's done carefully).


> how do you do it actually for nontrivial preconditions like "this list must be sorted"?

This depends on your data model, of course. But for a list of integers you could do the following:

1. Have a unique data type that is the list of Deltas, plus the initial element (So for instance the list [5, 3, 6] would be encoded as (3, [2, 1]).

2. Provide a sort function that creates such a sorted list.

3. Make the sorted list your input parameter.

This is obviously oversimplified, but I hope you get the idea.

A cheaper alternative is to

1. Make an opaque datatype "sorted list", together with a function that translates this type to a normal list. Implemen this type just as a list, but keep the implementation private.

2. Provide a function sort, that is the only function that can yield that type.

3. Demand that type as input.


Encapsulation aided by types and module interfaces.

In Reason/OCaml, you can create a module interface (.rei or .mli) which makes the type opaque to functions outside the module. So instead of saying `type t('a) = list('a)`, it'll just say `type t`.

The compiler relies on this type information to decide whether functions are well-typed. So if an external module presumes to know the structure of the type and does an operation on it, it becomes a type error because the compiler simply doesn't know about the actual type. This is similar to encapsulation in OO where we don't expose a field to the outside world, but here it is done by virtue of the type signature itself, which I found to be a more powerful guarantee of encapsulation.

The module can then expose functions like `append` which would be the only way you can manipulate the list. This function in-turn can ensure the postcondition, guaranteeing that the list stays sorted. At the point in which we want to use the list for functions not supported by our SortedList module, we can turn it into a regular list with a `to_list` function. Since the underlying type is already a list, the operation is virtually free. The function would look like `let to_list = (xs: t('a)) => (xs: list('a))`. It is an identity function, with just the type changed for the compiler.

Similar rules about `append` applies to the constructor: we can create a new `SortedList` only with a `SortedList.make` which can ensure the postcondition. There will be no other way, thanks to the type being hidden, to create a value of the `SortedList.t` type.


I would use the “smart constructor” pattern for this: https://draptik.github.io/posts/2020/02/10/fsharp-smart-cons...

Things like that require runtime logic, there’s no way around that.


It's idiomatic to use "opaque types" to achieve this in F#. In practice it is actually pretty analogous to the concept of a "constructor" in OOP.


The difference between doing functional programming in C# vs doing functional programming in F# is subtle but important. A true FP language like F# will not allow code that introduces certain classes of errors FP is designed to prevent. Whereas in C#, a developer needs to be really careful not to introduce those errors even when following FP style. C# will always allow mutable states, null values, global variables, to name a few.


As other replies to this comment describe, we make heavy use of opaque types where runtime enforcement of safety is need. Some examples: PositiveFloat, PositiveDecimal, NonEmptyMap, NonEmptySet, NonEmptyList, KeyedSet.


> While F# allows C#-like OOP, and while this can be an initial stepping stone in the path towards F#, you must go all the way.

I'd be less charitable and say that OOP in F# is a tedious, verbose mess. Functional programming in F# is extremely concise, at the expense of OOP. I wrote a parser/lexer in F#, to be used from C#, and ended up rewriting it in C# instead of dealing with the interop. I'm hoping that some day, C# will eventually have F#'s pattern matching power. They're slowly introducing more and more features to do it, and there's no major technical reason why C# wouldn't be able to.


The way we do it at $WORK is to do a proper F# API and then expose a fluent C# API that wraps it. Our APIs are usually based on constructing descriptions - which a fluent API can do just as well as a "native" F# one - and then we provide a very few functions which interpret those descriptions. The hard interop is in constructing the descriptions, because C# likes objects to look very different from F#; we just give up and expose two separate APIs for constructing the F# objects.


Agreed. You can't completely avoid it as we're running on a framework (and libraries) that's based on C#, but we architect our code such that these messy edges that interface with the outside world are implemented once, creating a nice walled garden for the rest of the F# code inside.


> "Make illegal states unrepresentable" > (as is true with learning any functional language)

...unless you are using a language where types are not part of the contract and not used in dispatching, such as Elixir.

I have mixed feelings about that because, on the other hand, in runs on the BEAM VM and as long as lack of typing leads to a proper crash, you may be OK as long as your code is written correctly.


Chaldal (https://chaldal.tech) YC S15 | Remote | Full-time

We build systems and infrastructure in the developing world. Our primary offering is a vertically-integrated 15-minute grocery delivery service, built in the world's most densely populated city, Dhaka, and looking to expand to other geographies. To support this system, we work on supply chains that connect farmers, wholesale markets, logistics networks and commodity exchanges. We work with the World Food Program in feeding the world's largest refugee camp. We're a profitable company and we're backed by the World Bank.

Our stack: - F# (C# for some legacy services that we're moving to F#) - Orleans - TypeScript - React, React Native - Service Fabric

We have fun building IDE plugins, DSLs and new ways of programming. If interested, email me at tejas@chaldal.com.


Try F#


lock them up and dont give them any food


I've taken the approach of converting my models to XML, mostly because they map 1:1 from F#-land to XML-land, and I can use SQL Server's XML Indices, but most importantly, I can use XSLT to evolve my persisted models upon change change to F# code.

Then using a bit of F# Quotations, I can convert most match queries to XPath queries and query SQL Server directly (still work-in-progress).

But running into performance problems, so it's not 100% done.

http://stackoverflow.com/questions/41949177/f-data-types-sql...


Yeah, I did the first part a couple years ago too. I also put the whole thing behind a VCS so we'd have version-controlled data. But, yeah, it didn't scale well enough and I ended up dropping that for mongodb, and later for postgres.


Chaldal (YC-S15) | Senior Engineers / Architects | SF, Singapore | Fulltime, Onsite preferred / Remote considered

Build out entire tech ecosystems in developing countries.

We're a US company, currently focused on Bangladesh, and we're building out the infrastructure for all digital commerce. We're already the biggest tech company in the country by far, supported by the government, with our own warehouses, logistics fleet and a 400-person ground-team, about to break through from urban to rural areas.

We believe in lean yet strong engineering.

Apply if you're extremely passionate about computer science, Haskell, F# or LISP, or if you can't find sleep because the world isn't as integrated as it can possibly be.

You'll be responsible for your own business unit, and you will be managing junior engineers. MUST NOT be afraid to get into the dirty details of the bits and MUST be able to visualize the entire system.

Email: founders [at] chaldal [dot] com


We use Xamarin Forms a LOT for our internal and public facing apps. I started exploring it almost 2 years back, because native Android development just sucked, and C# has the async/await keywords, which is simply perfect for asynchronous operations in UI.

It has not been an easy road. After 2 years, I'm finally beginning to reap the benefits. The simple problem is this: this is another layer over the existing layers and it's very hard to get it right, especially if the underlying layers suck.

Just because you've learnt Xamarin Forms doesn't mean you can choose not to learn the underlying native platforms. You can skip over most of the details, but something will always come back to bite you, and then you have to go figure it out. Xamarin Forms works on top of Xamarin Android, that works on top of Android SDK and Android Tooling, which works on top of the JDK, which works on top of the OS you're developing on. So many places for something to go wrong, and usually presents itself in the form of a cryptic error at the top. Developing for iOS is considerably easier.

So there's still a fair amount of expertise to develop if you're completely new to mobile development. Take it for what it is -- an abstraction, and as with any abstraction, any concrete manifestation will have its issues, and you must be ready to roll up your sleeves to figure it out. And it does get keep getting better with every subsequent release.

But it does eventually help -- we have to get the complex bit right once, and then it simply works. Don't approach this like you would approach an Android app -- make sure you understand UI design best practices -- especially reactive design and data binding.

We also have .NET stack, so I'm finally in this beautiful world where all my logic is represented as C# Expression Trees on the server side, that gets serialized and pushed down to our Xamarin Forms Apps. Looking forward to WASM adoption, so I can finally get rid of that JavaScript mess.

So if you're writing a one-time app, and you just want to target Android/iOS, and you don't care how you've done it, no it doesn't make too much sense.

But if you're trying to make a long-term bet, in this awful fragmented device-oriented world, (and having to write the same app twice goes against the very nature of your existence), well that's my bet, I will be cautiously optimistic. If you're on .NET, it's a no-brainer -- there are simply too many other benefits to ignore, and philosophically very true.

The architecture itself (Forms, Xamarin.Android, Xamarin.iOS, Custom Renderers, Platform Effects, Bindings to access native libraries) is theoretically flawless (or very close to it), a work of art -- and I'm a sucker for theory, no matter the real world pain.


If these alien beings are built using javascript (as pictured above in the matrix-esque image) then we definitely have nothing to fear.

This phrase should defeat them: "Hi, welcome to undefined"


If they used JavaScript, the language's excellent floating point arithmetic would likely make them crash all the time and we will be safe.


Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: