F#中是否有一种以Clojure方式提取记录成员的值的方法?

vid*_*idi 6 f# clojure

在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。!

Chr*_*son 4

我的建议是这样的:

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)

不过,这种编码风格对我来说不太明显。我更愿意保留模块名称。