There is a common problem that F# does not natively support infix-style use of functions that is available in Haskell:
isInfixOf :: Eq a => [a] -> [a] -> Bool
isInfixOf "bar" "foobarbaz"
"bar" `isInfixOf` "foobarbaz"
The best known solution for F# can be found here:
let isInfixOf (what:string) (where:string) =
where.IndexOf(what, StringComparison.OrdinalIgnoreCase) >= 0
let found = "bar" |>isInfixOf<| "foobarbaz"
Also, it is easy to improve it a bit, employing native operators precedence:
let ($) = (|>)
let (&) = (<|)
let found = "bar" $isInfixOf& "foobarbaz"
There's also XML-ish </style/>
, described here.
I would like to find a better solution, with the following criteria:
It should not destroy associativity (support chaining):
let found = "barZZZ" |>truncateAt<| 3 |>isInfixOf<| "foobarbaz"
Optionally, it should support functions taking tuples:
let isInfixOf (what:string, where:string) = ...
// it will not work with |> and <|
Optionally, it should gracefully handle functions/3:
val f: 'a -> 'b -> 'c -> 'd = ...
let curried = a |>f<| b c
// this wouldn't compile as the compiler would attempt to apply b(c) first
P.S. Various coding tricks are also welcome as I believe the good one (when checked by the F# Dev team) can be a part of the language in the future.
I agree that the ability to turn functions into infix operators in Haskell is neat in some situations. However, I'm not sure if this feature would fit well with the usual F# programming style, because the same can be achieved using members.
For example, let's take your snippet that uses truncateAt
and isInfixOf
:
let found = "barZZZ" |>truncateAt<| 3 |>isInfixOf<| "foobarbaz"
If we define TruncateAt
and IsInfixOf
as extension methods of string
, then you can write:
let found = "barrZZZ".TruncateAt(3).IsInfixOf("foobarbaz")
This version is shorter and I personally think it is also more readable (espcially to someone with .NET programming background as opposed to Haskell background). You also get IntelliSense when you hit .
, which is a nice bonus. Of course, you have to define these operations as extension methods, so you need to more carefuly consider the design of your libraries.
For completeness, the extension methods are defined as follows:
type System.String with
member what.IsInfixOf(where:string) =
where.IndexOf(what, StringComparison.OrdinalIgnoreCase) >= 0
member x.TruncateAt(n) =
x.Substring(0, n)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With