4 ms·
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 |> e
by arwhatever 8y ago
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 some more.
I suspect that if I were to try to hide an async workflow behind such an arrangement that the parameter-rearrangement layer might create a greater cost than a benefit.
But still, it's really neat that the language allows for this sort of attempt.
- Tarean 8y agoWith some combinators you can indeed do this for any expressions, haskell has a tool that does this transformation automatically http://pointfree.io http://pointfree.io This can quickly become unreadable but used well it can hide some noise and meaningless variable names.
- jcmoscon 8y agoThis is why I love Haskell. You can easily define your own "|>" operator: (|>) :: a -> (a -> b) -> b x |> f = apply x f
- platz 8y agobut 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 more often. Or you can try to write in a style that prefers right-to-left.
- sparkie 8y agoIf the left to right order is preferred, Haskell has Control.Category.(>>>) f >>> g = g . f Works for any instance of Category.
- solinent 8y agog f x would not be the same as (g . f) x you need the right associative function application operator $, ie. g $ f x or simply g (f x)
- platz 8y agoi know that, i was just highlighting the appearance of the order of the letters without considering associativity.
- joel_ms 8y agoI got used to this in Haskell, but I have to say that Elm's solution is pretty elegant: Elm: Haskell: f <| g <| x == f $ g $ x -- application f << g == f . g -- composition x |> 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 < in the operator. I've actually done this quite a lot when refactoring code in Elm lately, there's something visual and intutive about it that I like. It makes it easier to mix left-to-right and right-to-left in the same code, while keeping it obvious what's going on. I've found that certain parts, that scan/read better as imperative steps (think chains of List.map, Maybe.map, <MonadlikeModule>.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.
- ionforce 8y agoIt feels so weird that I can understand this discussion now. I used to think that all these Haskell discussions were garbage. But now I get it. It's still very inaccessible, in my opinion. But I'm working on something to help change all that.
- erk__ 8y agoIt is pretty much as easy, and in my opinion more readable to do that in F# let (|>) x f = f x
- bunderbunder 8y agoI'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.
- cinnamonheart 8y agoScala uses this syntax and I find it to be quite nice: (0 to 100).map(someFunc(arg1, arg2, _, arg3))
- jgamman 8y agoas does Mathematica. v useful for pattern matching as the hook for the function.
- brianberns 8y agoThat can be fun and is only one step away from "point-free style". Just leave out the inputs altogether and switch to direct function composition: let myFunc = step1 >> step2 >> step3 >> etc Personally, I often find point-free to be a little too terse, but occasionally it's much clearer than "regular" code. https://en.wikipedia.org/wiki/Tacit_programming https://en.wikipedia.org/wiki/Tacit_programming