News for hackers. Stuff that matters.
Re:A philosophical difference between Haskell and Lisp (2015) by behnamoh on Sunday August 02, 2020 @04:59PM (#24031695)
Is there something similar to (->>) in Haskell?

Edit: corrected “—>”.

Re:A philosophical difference between Haskell and Lisp (2015) by nimih on Sunday August 02, 2020 @05:59PM (#24032137)
Assuming that (-->) is either a typo of Clojure's ->> or ->, or some CL macro that operates the same (I don't know any CL, admittedly), in Haskell there is the somewhat common & (as in, available in the standard library and the widely-used lens library, but not part of the prelude and a lot of folks seem to eschew it in favor of composing in "the other direction" with . and $), which is defined as `flip ($)` (i.e. reverse function application) and visually ends up working the same as ->>:

    myList
    & map someFunction
    & filter somePredicate
    & sum
Other ML-ish languages typically provide this operator but under a different name, |> being a common one. One important note is that the mechanics here are a bit different than threading macros in lisp, since you're explicitly building the AST you want and using operator precedence (and implicit/automatic currying) to get the visual effect, rather than calling a rewrite rule. This means you can't have a straightforward reproduction of Clojure's -> macro, although in practice this never really matters, and when it does you can still fake it with flip (or, more readably, parens and a lambda).
Re:A philosophical difference between Haskell and Lisp (2015) by eru on Monday August 03, 2020 @12:00AM (#24034103)
If you really want to, Haskell also has a few macro systems. They are just not used nearly as much as in Lisp.
Re:A philosophical difference between Haskell and Lisp (2015) by dwohnitmok on Sunday August 02, 2020 @06:02PM (#24032160)
This comes for free from Haskell's automatic partial application (that arises from Haskell's pervasive use of function currying). So several different Haskell variants of Clojure's `compose` correspond to different versions of Clojure's threading macros.

Clojure's threading macros arise because it's a little bit more awkward in Clojure to partially apply functions (either anonymous functions with # or use `partial`) and it reads more fluently to just use threading macros there.

However, Clojure can do fancier things with variants of the common threading macros (https://github.com/rplevy/swiss-arrows)

Re:A philosophical difference between Haskell and Lisp (2015) by thom on Sunday August 02, 2020 @06:11PM (#24032223)
What's the syntax in Haskell for thread-first (-> in Clojure) which inserts the result of the previous operation as the first argument, versus thread-last (->>) which inserts it at the end, so is more amenable to composed curried functions?
Re:A philosophical difference between Haskell and Lisp (2015) by dwohnitmok on Sunday August 02, 2020 @06:44PM (#24032441)
Ah I was wrong! That's what I get for not coding in Haskell in a year and not checking my answer with GHC.

Function application always has higher precedence than infix operators so I can't emulate thread-first with functions in Haskell. If that wasn't the case, this would work (this was what I was thinking of)

    (|*>) :: b -> (a -> b -> c) -> (a -> c)
    (|*>) x f = (\y -> f y x)

    xs = 5
        |*> take [1, 2, 3]
Otherwise, I can come close with this.

    import Data.Function ((&))

    infix 9 *-
    (*-) :: (a -> b -> c) -> b -> (a -> c)
    (*-) f x = (\y -> f y x)

    xs :: [Int]
    xs = 5
        & take *- [1, 2, 3]
        & filter (/= 1)
        & head
        & take *- [1, 2, 3]
Re:A philosophical difference between Haskell and Lisp (2015) by thewakalix on Sunday August 02, 2020 @09:11PM (#24033204)
Using right-associativity of function types, and by sugaring the lambda into another function argument, we can rewrite this as

  (*-) :: (a -> b -> c) -> b -> a -> c
  (*-) f x y = f y x
This reveals that (*-) is simply flip, which is in the Prelude (re-exported from Data.Function). Alternatively, Hoogling the original type signature will reveal the same thing.

So the example doesn't require any new functions:

  import Data.Function ((&))

  xs :: [Int]
  xs =
    5
      & flip take [1, 2, 3]
      & filter (/= 1)
      & head
      & flip take [1, 2, 3]
In general, it's common in Haskell to use flip, curry/uncurry, and other higher-level functions to manipulate functions so they fit into the needed context.
Re:A philosophical difference between Haskell and Lisp (2015) by eru on Monday August 03, 2020 @12:03AM (#24034116)
If you don't like flip, you could also do

  xs :: [Int]
  xs =
    5
      & (`take` [1, 2, 3])
      & filter (/= 1)
      & head
      & (`take` [1, 2, 3])
But I'm not sure that's a better style than flip.

I really like `on` from Data.Function, too.

Re:A philosophical difference between Haskell and Lisp (2015) by johnday on Monday August 03, 2020 @05:51AM (#24035811)
For maximum readability I'd be tempted to write the lambdas explicitly.

  xs =
    5
      & (\n -> take n [1, 2, 3])
      & filter (/= 1)
      & head
      & (\n -> take n [1, 2, 3])
Re:A philosophical difference between Haskell and Lisp (2015) by eru on Monday August 03, 2020 @11:35PM (#24046287)
That might be a wise choice.

It depends on what you are used to and your tolerance thresholds.

In a code base I worked on professionally, I came across the following idiom

    f a b `flip` d
which at first used to confuse me to no end. Later I figured out that you are supposed to read it as:

    f a b <place-holder> d
and thus

    \c -> f a b c d
In the same vein that Scala uses an underscore in somewhat implicit anonymous function syntax.

I still wasn't really happy with that usage, but at least I see why someone thought it would make sense.

(Mostly I wasn't so happy because it only works for the penultimate argument. If the syntax had worked out so that

    f a `flip` c d
would mean

    \b -> f a b c d
I would have been more amenable to the idiom. But you need the ugly

   f a `flip` c `flip` d
for that case. And that's clearly worse than the lambda syntax.
Re:A philosophical difference between Haskell and Lisp (2015) by johnday on Sunday August 09, 2020 @01:40PM (#24101292)
Oh good lord, that's horrible!
Re:A philosophical difference between Haskell and Lisp (2015) by truculent on Monday August 03, 2020 @06:04AM (#24035904)
I think the Prelude answer would be to use `flip`[1], along with composition (`.`) or application (`$`) as usual.

    flip :: (a -> b -> c) -> b -> a -> c 

[1]: https://hackage.haskell.org/package/base-4.14.0.0/docs/Prelu...
Re:A philosophical difference between Haskell and Lisp (2015) by rbonvall on Sunday August 02, 2020 @05:22PM (#24031884)
You can create it yourself:

    Prelude> s ->> f = f s
    Prelude> [1..100] ->> take 10 ->> filter (not . odd) ->> drop 3
    [8,10]
Re:A philosophical difference between Haskell and Lisp (2015) by jim-jim-jim on Sunday August 02, 2020 @05:39PM (#24032010)
I think `&` is this function. In Data.Function.
Re:A philosophical difference between Haskell and Lisp (2015) by eru on Monday August 03, 2020 @12:06AM (#24034135)
Or you can use >>> from Data.Function, if you prefer to go point-free.
Re:A philosophical difference between Haskell and Lisp (2015) by embwbam on Sunday August 02, 2020 @05:54PM (#24032107)
Re:A philosophical difference between Haskell and Lisp (2015) by truculent on Sunday August 02, 2020 @05:34PM (#24031970)
I think there are some pipe-like operators in the popular Lens library (and presumably others as well). However, writing Haskell, you quickly get used to everything being backwards.
Re:A philosophical difference between Haskell and Lisp (2015) by thom on Sunday August 02, 2020 @06:13PM (#24032234)
I find the Lens operators in Haskell just the most hilarious API in all of computing, even knowing that there is some sense to it.
Re:A philosophical difference between Haskell and Lisp (2015) by dllthomas on Sunday August 02, 2020 @07:06PM (#24032569)
I very much enjoyed a Kmett talk where he described needing to parameterize some lens thing with an index, a monad it would operate under, the source focus, the target focus, and three different containing structures, with some pieces repeated... and then realizing the type arguments said `i m a s t a b u` and decided he had probably gone too far.
Re:A philosophical difference between Haskell and Lisp (2015) by eru on Monday August 03, 2020 @12:08AM (#24034145)
What's interesting is that Ed Kmett isn't even a dyed in the wool Haskeller. He has more than a foot in the C++ world.

He's quite brilliant, but I still haven't really gotten used to the full power of lenses, yet. I only used them in simple ways.

Re:A philosophical difference between Haskell and Lisp (2015) by truculent on Monday August 03, 2020 @05:59AM (#24035864)
While I have found the majority of my interactions with Haskell (and ML family languages) deeply satisfying, I have never really used Lens in anger, having been put off each time I've tried to get into it. Although, I remain slightly simpathetic since - as you say - there is some theory underlying it all.

I may be mistaken, but I think I have seen a handful of "Lens-lite" type libraries for use in production since it's such a large library, which seems.. uh.. suboptimal.

Re:A philosophical difference between Haskell and Lisp (2015) by garethjrowlands on Sunday August 02, 2020 @05:25PM (#24031899)
Not really. In the example, function composition, `.`, joins the functions together.

You can smash a list of functions together but they'd all have to take and return the same type, and the list would introduce commas and square brackets, so it wouldn't look quite the same.

Re:A philosophical difference between Haskell and Lisp (2015) by eru on Monday August 03, 2020 @12:09AM (#24034150)
You might be able to do some type trickery with heterogeneous lists? But I don't think it would be worth it.
Re:A philosophical difference between Haskell and Lisp (2015) by Ixiaus on Sunday August 02, 2020 @05:20PM (#24031865)
`.` is function composition in Haskell (used in the example).
Re:A philosophical difference between Haskell and Lisp (2015) by eru on Monday August 03, 2020 @12:09AM (#24034153)
Interestingly function composition is also the mapping operator (fmap) for the corresponding functor.