F#中的Haskell样式到中缀运算符

byt*_*ter 5 f#

有一个常见的问题是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/>,在这里描述.

我想找到一个更好的解决方案,具有以下标准:

  • 单个字符运算符(或一对)不破坏常用运算符;
  • 它应该是相同的字符,同样严重的重音(后引号)字符在Haskell中服务;
  • 它不应该破坏关联性(支持链接):

    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#编程风格,因为使用成员可以实现相同的功能.

例如,让我们使用您使用的代码段truncateAtisInfixOf:

let found = "barZZZ" |>truncateAt<| 3 |>isInfixOf<| "foobarbaz" 
Run Code Online (Sandbox Code Playgroud)

如果我们定义TruncateAtIsInfixOf作为扩展方法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)

  • @Tomas:虽然我同意你的中缀调用不适合F#风格的前提,但方法是一个非常差的替代品; 你放弃了功能的所有好处. (6认同)
  • @ 7sharp9:名称_和_符号的关键是熟悉.`adsfkj`并不比`〜!@>更好. (3认同)
  • @ 7sharp9我可以更好地理解运营商,我希望我们的选择不仅限于新手.你能从`FParsec`建议`(.>>.)`,`(.>>)`,`(>>.)`的名字?假设你自己不是新来者并且没有提供任何链接. (3认同)
  • 好吧,有一些运算符被认为是惯用的 - 比如`|>`(也可能也是`<|`,虽然我不经常使用这个).我很满意这些.其他语言有其他惯用结构......有时这些直接映射到F#,有时它们不会.我认为Haskell中缀函数表示法没有. (2认同)
  • @TomasPetricek:我同意; 一流的方法甚至更好. (2认同)
  • 对不起,我没有注意到这些评论,直到有人在这里重新发布链接.它们都有真实的名字和描述,.>>.是tupleTwo,.>> returnLeft等等,我正在制作的是你必须在它们不清楚时查找符号的名称和含义.IntelliSense也不适用于符号,但它适用于非符号. (2认同)