Closed tureluren closed 3 years ago
Hello, @rifraf93, and welcome to the community. :wave:
In Haskell, <>
is an infix operator:
> "foo" <> "bar"
"foobar"
The lovely thing about <>
is that one need not consider nesting:
> "foo" <> "bar" <> "baz"
"foobarbaz"
Sanctuary gives us two equally valid ways of expressing the above, both noisy:
> S.concat (S.concat ('foo') ('bar')) ('baz')
'foobarbaz'
> S.concat ('foo') (S.concat ('bar') ('baz'))
'foobarbaz'
In Haskell, infix operators can also be treated as regular functions. The function equivalent of <>
is (<>)
:
> :type (<>)
(<>) :: Semigroup a => a -> a -> a
This is exactly the type of S.concat
! Let's see how (<>)
behaves:
> (<>) "foo" "bar"
"foobar"
The behaviour of S.concat
is thus consistent with that of (<>)
.
Haskell supports sectioning:
> ("foo" <>) "bar"
"foobar"
> (<> "bar") "foo"
"foobar"
Sectioning permits partial application of either argument:
> map ("prefix-" <>) ["foo", "bar", "baz"]
["prefix-foo","prefix-bar","prefix-baz"]
> map (<> "-suffix") ["foo", "bar", "baz"]
["foo-suffix","bar-suffix","baz-suffix"]
Without sectioning, we must resort to using S.flip
:
> S.map (S.concat ('prefix-')) (['foo', 'bar', 'baz'])
[ 'prefix-foo', 'prefix-bar', 'prefix-baz' ]
> S.map (S.flip (S.concat) ('-suffix')) (['foo', 'bar', 'baz'])
[ 'foo-suffix', 'bar-suffix', 'baz-suffix' ]
I usually prefer functions to operators, as operator precedence is a source of incidental complexity. In this case, though, I do miss sectioning!
Thank you for your quick response @davidchambers.
Though, now i'm confused about S.lte. <=
is also an infix operator in haskell. So following your reasoning about S.concat, which was very clear, leads me to believe that one should resort to using S.flip
with S.lte
as well:
// Should be [2, 3]
> S.filter (S.lte (2)) ([1, 2, 3])
[ 1, 2 ]
// Should be [1, 2]
> S.filter (S.flip (S.lte) (2)) ([1, 2, 3]);
[ 2, 3 ]
Since in haskell:
> filter (2 <=) [1, 2, 3]
[2, 3]
> filter (<= 2) [1, 2, 3]
[1, 2]
Using S.concat
with S.flip
is of course only a small effort, it just confused me a little bit.
Thank you
S.concat
has two common use cases: prepending and appending. JavaScript does not support sectioning, so we are forced to favour one use case (arbitrarily). It will be necessary to flip the function about half the time, whichever use case we favour. The deciding factor is that S.concat ('foo') ('bar')
evaluating to 'foobar'
is the more natural of the two possibilities.
That makes sense, thank you for explaining.
Hello, as a newbie in functional programming I can't get my head around something.
S.lte returns true if the second argument is less than or equal to the first. Which comes in handy when filtering data like in your example:
So why does S.concat not work in the same fashion?
Is this intentionally?