7 ms·
I'm relatively an FP newbie, and I have a few questions. 1. I've never seen the "pipe" notation you talk about in any lang except bash, which is not an FP righ
by davidatbu 5y ago
I'm relatively an FP newbie, and I have a few questions.
1. I've never seen the "pipe" notation you talk about in any lang except bash, which is not an FP right? In which languages does "|" denote function application?
2. Aren't dependent types orthogonal to whether a language is functional? Just to make sure we're on the same page on what dependent types mean, I wanna give a example (a contrived one, sorry) of dependent types in Python.
from typing import overload, Literal
@overload
def str_if_zero(num: Literal[0]) -> str: ...
@overload
def str_if_zero(num: int) -> int: ...
@overload
def str_if_zero(num: int) -> int | str:
if num == 0:
return "That's a zero"
return num
- lostcolony 5y agoElixir, Elm, Ocaml, Haskell, and F# all have a pipe like operator for function composition (though the actual operator varies).
- madcaptenor 5y agoR also has it, if you count R as a functional language.
- 6gvONxR4sf7o 5y agoI think libraries are just as relevant as languages, and dplyr’s pipes are wildly popular and (more to the point) even idiomatic R at this point.
- madcaptenor 5y agoActually base R has a pipe operator now. (I still use the dplyr pipe, just out of familiarity.)
- uoaei 5y agoAs does Julia
- pharmakom 5y agoR is a surprisingly functional language!
- davidatbu 5y agoGot it. Thanks!
- thaumasiotes 5y agoClojure has the -> macro: https://clojuredocs.org/clojure.core/-%3E https://clojuredocs.org/clojure.core/-%3E It does the same thing, but it's much more awkward to use.
- eigenhombre 5y agoAs a daily user of -> and ->>, I am curious what you find awkward about them.
- thaumasiotes 5y agoYou have to plan to use them in advance. With a pipeline operator you can figure out the command you want at one stage and then tack on another part of the pipeline without needing to go back and alter the way you began the line.
- chaorace 5y agoThere's also a Stage 2 proposal for adding a pipe operator to JS[1] [1]: https://github.com/tc39/proposal-pipeline-operator https://github.com/tc39/proposal-pipeline-operator
- mdoms 5y agoF# and Ocaml are good examples from my limited functional experience. https://stackoverflow.com/questions/2177110/in-f-what-does-pipelining-mean/2177129 https://stackoverflow.com/questions/2177110/in-f-what-does-p...
- davidatbu 5y agoThanks!
- 1-more 5y agoThe pipeline operator |> exists in Elm[0]. It is available in bash as & and the popular (in my limited experience) package flow[1] also implements it as |> for readability. It is a proposed addendum to Javascript[2] but I have no idea how seriously the JS powers-that-be are taking that. The example you gave of Python doesn't have tagged union. I really don't know much at all about Python so maybe the type checker can tell you that you're handling all the cases, but with tagged union types you can have to handle every possible output of `str_if_zero` when calling it. That doesn't have to be an FP thing but I only find it when doing Elm and Haskell in my experience. [0] https://elm-lang.org/docs/syntax#operators https://elm-lang.org/docs/syntax#operators [1] https://hackage.haskell.org/package/flow https://hackage.haskell.org/package/flow [2] https://github.com/tc39/proposal-pipeline-operator https://github.com/tc39/proposal-pipeline-operator
- 1-more 5y agoFor some reason I wrote "bash" when I meant "Haskell" in the second sentence. Sorry about that.
- agumonkey 5y agooutside `|` there's the threading macro in lisps (or else) (-> x f g h ...)
- deleted 5y ago[deleted]
- kjeetgill 5y ago> which is not an FP right? > Aren't dependent types orthogonal to whether a language is functional? You're correct and I think that's kinda the parent's point. I think what the OP is saying is that the much of the syntax ergonomics are orthogonal to FP, which means they don't have to be as weird/frustrating/unusual/insert preference/unergonomic as they are. A good example is how piping vs nesting are different syntaxes for function composition: x|A|B|C vs C(B(A(x))) The former might feel more comfortable, familiar, and left-to-right readable for someone new to FP. That said I think a few language do use piping. F# has |> and I think Clojure used >>> maybe? -- signed, humble java programmer.
- chitowneats 5y agoClojure has two primary macros for this, thread-first (->), and thread-last (->>). They enable you to write pipe transformations and in my opinion make the code much more readable.
- thaumasiotes 5y ago> piping vs nesting are different syntaxes for function composition: x|A|B|C vs C(B(A(x))) > The former might feel more comfortable, familiar, and left-to-right readable for someone new to FP. C(B(A(x))) is the syntax introduced in school, but note that if you continue on in algebra the notation flips from C(B(A(x))) to x_{ABC}. Everyone agrees that it's easier to list the transformations in the order they happen.
- chadrs 5y ago(2) No, dependent types are not the same as overloading. Basically it's when the type depends on the values; so like having a type for odd numbers or having an array that knows its length at compile time (for example to avoid array out of bounds exceptions at compile time)
- 6gvONxR4sf7o 5y ago1. Others have answered it well. Tons of languages have pipe operators. I used | in my example because I figured more readers will recognize bash piping than other notations. 2. Yes that's what I mean by dependent types, where types depend on values, like f(0): string and f(1): int. And yes, they totally are orthogonal. However, pure functional programming tends to lean on its type system more than other styles, in my experience. But then without dependent types, something as simple as loading a CSV gets hairy relative to something like pandas's pd.read_csv. Maybe others can go into why pure FP and static typing go so much together, but I gotta get back to work.
- deleted 5y ago[deleted]
- dwohnitmok 5y agoDependent types are not totally orthogonal of FP. They generally require immutability and function purity to work well and become extremely difficult to work with in the absence of those features. See e.g. https://shuangrimu.com/posts/language-agnostic-intro-to-dependent-types.html#why-functional https://shuangrimu.com/posts/language-agnostic-intro-to-depe...
- guerrilla 5y agoYeah, type checking becomes undecidable otherwise and the compiler can also become vulnerable but Rust says they're going to try, so we'll see.
- dwohnitmok 5y agoWell it's luckily a little better than that. Type checking doesn't have to be undecidable and the compiler doesn't have to be vulnerable because you don't have to execute any side effects in the compiler even if the code is meant to execute any side effects at runtime. It's more that the utility of dependent types is generally restricted to functions that are pure and deal with immutable values, which means one possibility is to specially mark which of your functions are allowed to be used in a dependent type and which aren't. But the fragment of your program that can be used in dependent types is generally going to be a pure FP fragment.
- guerrilla 5y agoSide effects aren't the only reason the compiler can be undecidable though. It depends on the type system, not just referential transparency. Look at Cayenne or ATS. Also, don't forget it's possible to still possible to DoS the system (although this is already more than possible with C++ and such, so what are we complaining about.) Yeah, dependent types would be nonsensical for code that isn't functional. Marking which parts are and aren't is a good idea. Idris did something similar for totality checking. I think it'd be nice to have a system which differentiated between functions and procedures though.
- gpderetta 5y agoh(x).f().g() Is also very common and I would say it counts, especially if the language support something like extension methods.
- chriswarbo 5y ago> especially if the language support something like extension methods Extension methods are a bit of a hack (although useful!); a cleaner approach is https://en.wikipedia.org/wiki/Uniform_Function_Call_Syntax https://en.wikipedia.org/wiki/Uniform_Function_Call_Syntax although I've not personally used a language which supports it :(
- gpderetta 5y agoI'm a big fan of UFC myself.
- chromatin 5y agoI don’t know if I would say it’s very common(?) but it was introduced as a named concept (“uniform function call syntax”) AFAIK in D and is also a feature of Nim https://tour.dlang.org/tour/en/gems/uniform-function-call-syntax-ufcs https://tour.dlang.org/tour/en/gems/uniform-function-call-sy...
- chromatin 5y agoSome languages like OCaml have “pipeline” operator like `|>`, others like D allow you to chain function application `f.g.h()` instead of `h(g(f()))` [0] https://www.cs.cornell.edu/courses/cs3110/2019sp/textbook/hop/pipelining.html https://www.cs.cornell.edu/courses/cs3110/2019sp/textbook/ho... [1] https://tour.dlang.org/tour/en/gems/uniform-function-call-syntax-ufcs https://tour.dlang.org/tour/en/gems/uniform-function-call-sy...