arliss_obsidian/fp/Language/Infix Operators/Directionality.md
Orion Kindel 3701b1e2f8
update
2024-09-23 18:56:55 -05:00

1.5 KiB

Most commonly used Infix Operators have flipped variants, e.g.

In general, right-to-left operators tend to be easier to refactor into & out of because they closely mirror the expressions they replace:

map (add 1) maybeNum
-- into
add 1 <$> maybeNum

foo (bar a)
-- into
foo <<< bar

Left-to-right, on the other hand, can read better to humans and plays better with pipelines containing both [[Bind|bind >>=]] and [[Functor|map <#>]].

Consider an expression piping Maybe String to split :: String -> Array String then Data.Array.NonEmpty.fromArray :: Array a -> Maybe (NonEmptyArray a), then toLower each element:

String.toLower
  <$> (
    Array.NonEmpty.fromArray
    =<< String.split "."
    <$> mStr
  )

We need to wrap the right hand of the last map because the precedence of =<< is 1 (the lowest) and the precedence of <$> is 4.

Written RTL, though, gives:

mStr
  <#> String.split "."
  >>= Array.NonEmpty.fromArray
  <#> String.toLower

This works because <#>'s Precedence (1) is the same as >>=. The lower precedence on flipped map means you'll often need more parentheses wrapping its arguments (..) <#> (..) >>= (..) as opposed to entire expressions .. <$> (.. =<< ..).

Personally, I try to stick to RTL except for expressions including bind.