问题描述
存在一个常见问题,即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.
例如,让我们来看一下使用truncateAt
和isInfixOf
的代码段:
For example, let's take your snippet that uses truncateAt
and isInfixOf
:
let found = "barZZZ" |>truncateAt<| 3 |>isInfixOf<| "foobarbaz"
如果我们将TruncateAt
和IsInfixOf
定义为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运算符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!