在Clojure中,我将编写上面的代码:
user=> (def points [{:x 11 :y 12} {:x 21 :y 22}])
#'user/points
user=> (map :x r)
(11 21)
Run Code Online (Sandbox Code Playgroud)
我可以这样做是因为:x可以用作函数。这是一个非常有用的功能
F#中的相同代码如下所示:
> type Point = {x : int; y: int};;
> let points = [{x=11;y=12}; {x=21; y=22}];;
> List.map (fun p -> p.x) points
val it : int list = [11; 21]
Run Code Online (Sandbox Code Playgroud)
因为我一直讨厌写匿名函数,所以发现自己这样写Point类型:
type Point =
{
x: int
y : int
}
static member getX p = p.x;;
Run Code Online (Sandbox Code Playgroud)
...这使我可以执行以下操作:
> List.map Point.getX points
Run Code Online (Sandbox Code Playgroud)
这仍然很混乱,因为我需要为我使用的每个记录成员编写一个吸气剂。
相反,我想要的是这样的语法:
> List.map Point.x points
Run Code Online (Sandbox Code Playgroud)
有没有一种方法,而不必编写凌乱的匿名函数(fun p-> px)或静态吸气剂呢?
更新:
顺便说一下,Haskell也和Clojure一样(实际上是相反的):
Prelude> data Point = Point { x :: Int, y :: Int}
Prelude> let p = Point { x = 11, y=22}
Prelude> x p
11
Run Code Online (Sandbox Code Playgroud)
更新2:
希望反对lambda的一个更明显的原因是一个示例,该示例在没有帮助的情况下无法进行类型推断:
type Point2D = { x : int; y : int}
type Point3D = { x : int; y : int; z : int}
let get2dXes = List.map (fun (p:Point2D) -> p.x)
let get2dXes' : Point2D list -> int list = List.map (fun p -> p.x)
let get2dXes'' (ps : Point2D list) = List.map (fun p -> p.x) ps
Run Code Online (Sandbox Code Playgroud)
...比诸如此类的方式不那么优雅:
let get2dXes = List.map Point2D.x
Run Code Online (Sandbox Code Playgroud)
我不想开始争论哪种语法更好。我只是真诚地希望有一些优雅的方法可以完成上述操作,因为我自己还没有找到任何人。
显然,我所能做的就是向F#的强大之神祈祷,以便在将来的版本中在类型类旁边添加这样的功能;)
更新3:
已经为将来的语言版本提出了此功能。https://fslang.uservoice.com/forums/245727-f-language/suggestions/5663326-syntax-for-turning-properties-into-functions感谢JackP。!
我的建议是这样的:
namespace Temp
type Point = { x:int; y:int }
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Point =
let x: Point -> int = fun p -> p.x
let y: Point -> int = fun p -> p.y
type Circle = { r: int; x: int; y: int }
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Circle =
let x: Circle -> int = fun c -> c.x
let y: Circle -> int = fun c -> c.y
let r: Circle -> int = fun c -> c.r
module test =
let p1 : Point = { x = 1; y = 2}
Point.y p1 |> printf "%i"
Run Code Online (Sandbox Code Playgroud)
如果您可以保证不重复使用记录字段名称,那么您可以使用AutoOpen如下属性:
namespace Temp
type Point = { x:int; y:int }
[<AutoOpen>]
module PointExt =
let x: Point -> int = fun p -> p.x
let y: Point -> int = fun p -> p.y
module test =
let points = [ { x = 1; y = 2}; { x=5;y=10} ]
points |> List.map x |> List.iter (printf "%i")
Run Code Online (Sandbox Code Playgroud)
不过,这种编码风格对我来说不太明显。我更愿意保留模块名称。
| 归档时间: |
|
| 查看次数: |
1153 次 |
| 最近记录: |