Be Brave Be Like Ukraine
Be Brave Be Like Ukraine

Reputation: 7735

Haskell style to-infix operator in F#

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:

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.

Upvotes: 6

Views: 1523

Answers (2)

Tomas Petricek
Tomas Petricek

Reputation: 243051

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)

Upvotes: 17

Daniel
Daniel

Reputation: 47904

let (|<) f x = f x
let f = sprintf "%s%s"
let x = "A" |> f |< "B" |> f |< "C" //"ABC"

Upvotes: 2

Related Questions