有一个常见的问题是F#本身不支持在Haskell中使用的函数的中缀式使用:
isInfixOf :: Eq a => [a] -> [a] -> Bool
isInfixOf "bar" "foobarbaz"
"bar" `isInfixOf` "foobarbaz"
Run Code Online (Sandbox Code Playgroud)
可以在此处找到最着名的F#解决方案:
let isInfixOf (what:string) (where:string) =
where.IndexOf(what, StringComparison.OrdinalIgnoreCase) >= 0
let found = "bar" |>isInfixOf<| "foobarbaz"
Run Code Online (Sandbox Code Playgroud)
此外,使用本机运算符优先级很容易改进它:
let ($) = (|>)
let (&) = (<|)
let found = "bar" $isInfixOf& "foobarbaz"
Run Code Online (Sandbox Code Playgroud)
还有XML-ish </style/>
,在这里描述.
我想找到一个更好的解决方案,具有以下标准:
它不应该破坏关联性(支持链接):
let found = "barZZZ" |>truncateAt<| 3 |>isInfixOf<| "foobarbaz"
Run Code Online (Sandbox Code Playgroud)可选地,它应该支持带元组的函数:
let isInfixOf (what:string, where:string) = ...
// it will not work with |> and <|
Run Code Online (Sandbox Code Playgroud)可选地,它应该优雅地处理函数/ 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
Run Code Online (Sandbox Code Playgroud)PS各种编码技巧也很受欢迎,因为我相信好的(当由F#Dev团队检查时)可以成为未来语言的一部分.
Tom*_*cek 17
我同意在Haskell中将函数转换为中缀运算符的能力在某些情况下是很好的.但是,我不确定这个功能是否适合通常的F#编程风格,因为使用成员可以实现相同的功能.
例如,让我们使用您使用的代码段truncateAt
和isInfixOf
:
let found = "barZZZ" |>truncateAt<| 3 |>isInfixOf<| "foobarbaz"
Run Code Online (Sandbox Code Playgroud)
如果我们定义TruncateAt
和IsInfixOf
作为扩展方法string
,那么你可以写:
let found = "barrZZZ".TruncateAt(3).IsInfixOf("foobarbaz")
Run Code Online (Sandbox Code Playgroud)
这个版本更短,我个人认为它更具可读性(特别是对于具有.NET编程背景而不是Haskell背景的人).当你点击时你也会获得智能感知.
,这是一个很好的奖励.当然,您必须将这些操作定义为扩展方法,因此您需要更仔细地考虑库的设计.
为完整起见,扩展方法定义如下:
type System.String with
member what.IsInfixOf(where:string) =
where.IndexOf(what, StringComparison.OrdinalIgnoreCase) >= 0
member x.TruncateAt(n) =
x.Substring(0, n)
Run Code Online (Sandbox Code Playgroud)