Live data from Hacker News

A Fairy Tale of F# and Durable Functions

hackernoon.com

21–30 of 32 posts

Re: A Fairy Tale of F# and Durable Functions

#21
post #18

Earlier quoted context omitted.

What I think is most interesting is that the thing that enables F# code to be so readable is exactly the thing that I thought would be its biggest readability problem when I first encountered it: The function call syntax and semantics. Specifically, the fact that there's no requirement to place any brackets around an invocation or its argument list, and the currying by default. But the same syntax is what makes parti…

I actually completely disagree about the explicit `do` blocks; as a consequence of that decision, you can't write functions that abstract over all monads, at least not easily. I like F#, but that has always been my main gripe for the two years that I did F# full-time. I realize that for business code that that isn't a super big deal, but it becomes an issue if you want to write generic libraries; the closest thing th…

It's been a while, but, IIRC, the issue there is that computation expressions in F# are more a way of binding functionality to the syntax in an explicit way, than a direct expression of monads (or applicative functors, or whatever). F# doesn't even have a monad type to abstract over in its standard library in the first place. So what you might want to do instead is define your own library for working with abstractions, and then supply a computation expression or two for binding the syntax to the types defined in that library.

But yeah, you'd still be stuck writing wrappers to mate any pre-existing types to the library. I'm not sure that's really even computation expressions' fault, so much as an inevitable implication of F#'s lack of any facility for ad-hoc polymorphism.

Re: A Fairy Tale of F# and Durable Functions

#22
post #18

Earlier quoted context omitted.

I actually completely disagree about the explicit `do` blocks; as a consequence of that decision, you can't write functions that abstract over all monads, at least not easily. I like F#, but that has always been my main gripe for the two years that I did F# full-time. I realize that for business code that that isn't a super big deal, but it becomes an issue if you want to write generic libraries; the closest thing th…

It's been a while, but, IIRC, the issue there is that computation expressions in F# are more a way of binding functionality to the syntax in an explicit way, than a direct expression of monads (or applicative functors, or whatever). F# doesn't even have a monad type to abstract over in its standard library in the first place. So what you might want to do instead is define your own library for working with abstraction…

While I agree that that's probably true behind the scenes, to define a new computation expression you still have to define the haskell-style "bind" and "return" functions, at least giving the impression to new F# engineers that it has some kind of generic monad type.

Re: A Fairy Tale of F# and Durable Functions

#23
post #8
post #7

Earlier quoted context omitted.

This is why I love Haskell. You can easily define your own "|>" operator: (|>) :: a -> (a -> b) -> b x |> f = apply x f

but nobody uses it because "function composition" reads the other way and tends to be preferable i.e. (g ∘ f)(x) = g (f(x)) // math (g . f) x = g (f x) // haskell g f x g f x // see how the g f x order always matches with the default application and composition notation. you can mess with the order and "turn the order of application "inside-out" but then you have to switch modes from left-to-right and right-to-left m…

I got used to this in Haskell, but I have to say that Elm's solution is pretty elegant:

  Elm:               Haskell:

  f  g |> f   ==   x & g  &  f    -- reverse application

       g >> f   ==       g >>> f    -- reverse composition
It's nice to be able to change between composition and application by changing between | and I've found that certain parts, that scan/read better as imperative steps (think chains of List.map, Maybe.map, .andThen etc.) often benefit from a reverse application and/or composition. Sort of to simulate the look of do notation since Elm doesn't have that. Smaller functional parts are better with regular application/composition. With the directional operators, this becomes quite ergonomical.

Probaly helps that I use (and enjoy, ymmv) a font with ligatures for these symbols.

Re: A Fairy Tale of F# and Durable Functions

#24
post #18

Earlier quoted context omitted.

What I think is most interesting is that the thing that enables F# code to be so readable is exactly the thing that I thought would be its biggest readability problem when I first encountered it: The function call syntax and semantics. Specifically, the fact that there's no requirement to place any brackets around an invocation or its argument list, and the currying by default. But the same syntax is what makes parti…

I actually completely disagree about the explicit `do` blocks; as a consequence of that decision, you can't write functions that abstract over all monads, at least not easily. I like F#, but that has always been my main gripe for the two years that I did F# full-time. I realize that for business code that that isn't a super big deal, but it becomes an issue if you want to write generic libraries; the closest thing th…

We use the asyncMaybe CE extensively in the Visual Studio tooling for F# and although it's a little bit of boilerplate, in practice we don't need to lift an Async into an Async very often. The worst example of this is probably this file: https://github.com/Microsoft/visualfsharp/blob/8ea71dd368401...

In most cases the APIs are uniform enough to where it's not a pain point.

Re: A Fairy Tale of F# and Durable Functions

#25
post #18

Earlier quoted context omitted.

I actually completely disagree about the explicit `do` blocks; as a consequence of that decision, you can't write functions that abstract over all monads, at least not easily. I like F#, but that has always been my main gripe for the two years that I did F# full-time. I realize that for business code that that isn't a super big deal, but it becomes an issue if you want to write generic libraries; the closest thing th…

We use the asyncMaybe CE extensively in the Visual Studio tooling for F# and although it's a little bit of boilerplate, in practice we don't need to lift an Async into an Async very often. The worst example of this is probably this file: https://github.com/Microsoft/visualfsharp/blob/8ea71dd368401... In most cases the APIs are uniform enough to where it's not a pain point.

My complaints are actually in the opposite direction, though I realize that I didn't explain this very well; I wanted to be able to use an Async in already-existing async functions that weren't doing anything specific to async. A lot of my async stuff was just doing let! to "unbox" and returning at the end.

In Haskell land I would have used something like (Monad m) => m a -> m b, and then I could throw any monad transformer into there.

Re: A Fairy Tale of F# and Durable Functions

#26
post #4

It is a nice article, but one thing I don't like is that it picks Event Driven Architecture without spelling out the reasons _why_. "We used Azure Storage Queues to keep the whole flow asynchronous and more resilient to failures and load fluctuation." That's not enough for me. I often encounter people building complex systems message queuing, despite failures being rare, retries being cheap and fast, and the hardware…

Hi, the author here. It's a good point and a valid concern, but I did an explicit choice here: I didn't want to make the article longer. I have a prequel post which describes my thinking of why durable functions make sense, including a primer for the event-driven approach: https://hackernoon.com/making-sense-of-azure-durable-functio...

Re: A Fairy Tale of F# and Durable Functions

#27

Earlier quoted context omitted.

I went through a phase where I tried making the entry point of each project or major module read like nothing more than: inputs |> step1 |> step2 |> step3 |> etc ... and it seemed mostly doable, although I would wind up needing a layer of parameter rearrangement functions to make it read quite that cleanly. I don't know if I have a concrete opinion on how it worked out - I suppose I need to get back into doing this s…

I've been wondering if there's any value in having a syntax for partial application that works more like: fun(arg1, _, arg3) where the "_" indicates a skipped argument. My thought being that, in return for being a little bit more syntax-heavy, you'd get several potential advantages: No need for parameter rearrangement functions, easier overloading, and the more explicit syntax might help with maintainability.

as does Mathematica. v useful for pattern matching as the hook for the function.

Re: A Fairy Tale of F# and Durable Functions

#29

If I may ask, which language is more functional feature wise, F# or OCaml?

"More functional" is not a precise term. However OCaml would fit most everyone's idea of "functional" more than F#. F# has to be compatible with the underlying .Net runtime, so it cannot have features like abstraction over modules, which is a very powerful functional abstraction in OCaml. F# also builds mostly on libraries built in C#, so unless you want to build wrappers on top of everything, you'll be doing a lot of OOP in F# as well. (Which I think is fine, I think OOP fits well in lots of cases and it's nice to be able to mix and match).

Re: A Fairy Tale of F# and Durable Functions

#30
post #7

Earlier quoted context omitted.

I went through a phase where I tried making the entry point of each project or major module read like nothing more than: inputs |> step1 |> step2 |> step3 |> etc ... and it seemed mostly doable, although I would wind up needing a layer of parameter rearrangement functions to make it read quite that cleanly. I don't know if I have a concrete opinion on how it worked out - I suppose I need to get back into doing this s…

This is why I love Haskell. You can easily define your own "|>" operator: (|>) :: a -> (a -> b) -> b x |> f = apply x f

It is pretty much as easy, and in my opinion more readable to do that in F#

  let (|>) x f = f x
Post reply on HN