在F#中,如何更改记录中属性的属性(语法?)

在F#中,如何更改记录中属性的属性(语法?),f#,F#,假设我有这样一个记录: type Page = { footersize: Size } 仅更改页脚大小高度的正确语法是什么 { page with footersize = ??? } 短暂性脑缺血发作 编辑#1:“大小”是框架元素的大小,即。, 在.Net世界中,大小是大小(宽度、高度),是一种结构,而不是记录。如下文所述, 这不起作用: {p with footersize = {p.footersize with Height = 96 * 0.5}} 错误:此表达式应具

假设我有这样一个记录:

 type Page = { footersize: Size }
仅更改页脚大小高度的正确语法是什么

 { page with footersize = ??? }
短暂性脑缺血发作

编辑#1:“大小”是框架元素的大小,即。, 在.Net世界中,大小是大小(宽度、高度),是一种结构,而不是记录。如下文所述, 这不起作用:

{p with footersize = {p.footersize with Height = 96 * 0.5}}   

错误:此表达式应具有类型“Size”,但此处为类型页。

最直接的方法是复制并更新整个对象:

let page' =
    { page with
        FooterSize = Size(page.FooterSize.Width, 100.)
    }
如果你有更深的巢穴,它会变得更难

type Page = { FooterSize: Size }
type Document = { Title: string; Page: Page }

let document = { Title = "Fun and Profit"; Page = { FooterSize= Size(10., 10.) } }
要更新高度,现在必须执行以下操作:

let document' = { document  with Page = { document.Page with FooterSize= Size(document.Page.FooterSize.Width, 100.) }}
那就从屏幕上消失了!有一个,允许您执行
{documentwithpage.FooterSize.Height=100.}
,但这还有一点距离

镜头 当然,我们可以通过简单地使用compose right操作符获得值:

let (w, h) = (getPage >> getFooterSize >> getWH) document
但设置并不能构成。 但只要使用三个简单的运算符,我们就可以得到非常可读的内容:

let get (getter, _) = getter
let set (_, setter) = setter

let (>=>) (get_ab, set_ab) (get_bc, set_bc) =
  get_ab >> get_bc,
  fun a c -> set_ab a (set_bc (get_ab a) c)
因为我们的镜头只是一对吸气剂和设置剂:

let pageL = getPage, setPage
let footerL = getFooterSize, setFooterSize
let sizeL = getWH, setWH
就这样。那些是我们的镜片。现在,我们可以使用我们定义的fish操作符(
=>
)合成这些镜头

let (footer_w, footer_h) = get (pageL >=> footerL >=> sizeL) document
let document' = set (pageL >=> footerL >=> sizeL) document (footer_w, 100.)
当然,你可以用更短的形式写一个镜头:

let pageL : Lens<Document, Page> = 
    (fun d -> d.Page), (fun d p -> { d with Page = p })
let pageL:Lens=
(fundd->d.Page),(fundp->{d with Page=p})

最直接的方法是复制并更新整个对象:

let page' =
    { page with
        FooterSize = Size(page.FooterSize.Width, 100.)
    }
如果你有更深的巢穴,它会变得更难

type Page = { FooterSize: Size }
type Document = { Title: string; Page: Page }

let document = { Title = "Fun and Profit"; Page = { FooterSize= Size(10., 10.) } }
要更新高度,现在必须执行以下操作:

let document' = { document  with Page = { document.Page with FooterSize= Size(document.Page.FooterSize.Width, 100.) }}
那就从屏幕上消失了!有一个,允许您执行
{documentwithpage.FooterSize.Height=100.}
,但这还有一点距离

镜头 当然,我们可以通过简单地使用compose right操作符获得值:

let (w, h) = (getPage >> getFooterSize >> getWH) document
但设置并不能构成。 但只要使用三个简单的运算符,我们就可以得到非常可读的内容:

let get (getter, _) = getter
let set (_, setter) = setter

let (>=>) (get_ab, set_ab) (get_bc, set_bc) =
  get_ab >> get_bc,
  fun a c -> set_ab a (set_bc (get_ab a) c)
因为我们的镜头只是一对吸气剂和设置剂:

let pageL = getPage, setPage
let footerL = getFooterSize, setFooterSize
let sizeL = getWH, setWH
就这样。那些是我们的镜片。现在,我们可以使用我们定义的fish操作符(
=>
)合成这些镜头

let (footer_w, footer_h) = get (pageL >=> footerL >=> sizeL) document
let document' = set (pageL >=> footerL >=> sizeL) document (footer_w, 100.)
当然,你可以用更短的形式写一个镜头:

let pageL : Lens<Document, Page> = 
    (fun d -> d.Page), (fun d p -> { d with Page = p })
let pageL:Lens=
(fundd->d.Page),(fundp->{d with Page=p})

尺寸的定义是什么?假设尺寸也是一个记录;而
Height
是一种
int
,它是一种内置的编写
{page with footersize={page.footersize with Height=10}}
的方式。如果您经常进行这种嵌套更新,还可以使用镜头抽象(例如,来自的镜头抽象)@Asti Size,如在.Net WPF中,is Size(Double,Double)初始化Size结构的新实例,并为其指定初始宽度和高度。@Mankarse--oops,不起作用。请参阅补充信息。谢谢。
Size
的定义是什么?假设
Size
也是一个记录;而
Height
是一种
int
,它是一种内置的编写
{page with footersize={page.footersize with Height=10}}
的方式。如果您经常进行这种嵌套更新,还可以使用镜头抽象(例如,来自的镜头抽象)@Asti Size,如在.Net WPF中,is Size(Double,Double)初始化Size结构的新实例,并为其指定初始宽度和高度。@Mankarse--oops,不起作用。请参阅补充信息。谢谢。这是我见过的最好的镜片解释。谢谢,谢谢,艾伦。如果你来自C#背景,总会有一段震惊期。但这很快就会过去。坚持下去!这是我所见过的镜头的最好解释。谢谢,谢谢,艾伦。如果你来自C#背景,总会有一段震惊期。但这很快就会过去。坚持下去!