本文介绍了F#中的Haskell样式to-infix运算符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

存在一个常见问题,即F#本身不支持 Haskell中可用的功能的infix样式使用:

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"

可以在此处找到有关F#的最著名解决方案:

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"

还有一个XML样式的</style/>,在此处中进行了描述.

There's also XML-ish </style/>, described here.

我想根据以下条件找到更好的解决方案:

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

  • Single character operator (or a pair) that does not destroy commonly used operators;
  • It should be the same character, likewise grave accent (back quote) character serves in Haskell;
  • 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 <|
    

  • (可选)它应正常处理functions/3:

  • 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.我也欢迎各种编码技巧,因为我相信好的(当由F#Dev团队检查时)可以成为将来该语言的一部分.

    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.

    推荐答案

    我同意在某些情况下将函数转换为Haskell中的infix运算符的能力很巧妙.但是,我不确定此功能是否适合通常的F#编程风格,因为使用成员可以实现相同的功能.

    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.

    例如,让我们来看一下使用truncateAtisInfixOf的代码段:

    For example, let's take your snippet that uses truncateAt and isInfixOf:

    let found = "barZZZ" |>truncateAt<| 3 |>isInfixOf<| "foobarbaz"
    

    如果我们将TruncateAtIsInfixOf定义为string的扩展方法,则可以编写:

    If we define TruncateAt and IsInfixOf as extension methods of string, then you can write:

    let found = "barrZZZ".TruncateAt(3).IsInfixOf("foobarbaz")
    

    此版本较短,我个人认为它也更具可读性(特别是对于具有.NET编程背景而不是Haskell背景的人).当您按下.时,您还将获得IntelliSense,这是一个不错的奖励.当然,您必须将这些操作定义为扩展方法,因此您需要更加谨慎地考虑库的设计.

    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)
    

    这篇关于F#中的Haskell样式to-infix运算符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

    08-16 00:28
    查看更多