如何使用 FSharpPlus.Lens 指定列表的索引?



文档的示例代码使用List._item定义了_pageNumber,但我似乎找不到它的使用示例。 我尝试了以下代码,但它给出了一个错误。

view (Book._pageNumber 1) rayuela // error

它将如何使用?

我看到了同样的事情:

没有与方法'零'匹配的重载"。

该问题是由_Some镜头引起的,它不适用于记录类型,因为它们没有默认值(即"零")值:

let inline _pageNumberOpt i b =
_pages << List._item i <| b
let pageOpt = view (_pageNumberOpt 1) rayuela   // this is fine
let page = view _Some pageOpt                   // this doesn't work, because the input is an Option<Page>
let x = view _Some (Some 1)                     // this works, because the input is an Option<int>

这似乎是 FSharpPlus 中的一个限制,文档中没有考虑到这一点。如果你想变通解决这个问题,你可以自己定义Page.Zero,然后示例将编译:

type Page =
{ Contents: string }
static member Zero = { Contents = "" }
let page = view (Book._pageNumber 1) rayuela
printfn $"{page}"     // output is: { Contents = "The End" }
let noPage = view (Book._pageNumber 5) rayuela
printfn $"{noPage}"   // output is: { Contents = "" }

仅当您请求不存在的页面时,才会调用Page.Zero,但无论如何都需要为编译器提供该页面。

(FWIW,根据我的经验,FSharpPlus是一种非常非常微妙的野兽。这是一个有趣的实验,但它很容易破裂。当它中断时,编译器错误令人难以置信。

从技术角度来看,布莱恩的回答非常准确,但在概念上忽略了最重要的一点:您正在"查看"部分镜头(也称为棱镜),而不是"预览"它。这不是F#+的限制,这只是镜头的行为方式。

一些背景:棱镜或部分镜头就像一个可能会失效的镜头,所以原则上你不能对它们使用view操作,因为这是一个总是成功的操作,或者更好地说不考虑失败,你应该使用preview操作返回一个选项。

合成规则规定,合成的结果:

  • 带镜头的镜头是镜头
  • 带棱镜
  • (或相反)的透镜是棱镜
  • 镜的棱镜是棱镜

也就是说,一旦组合链中有一个棱镜,结果就会是一个棱镜。

在我们的例子中,我们有_pages << List._item i << _Some透镜,透镜由棱镜组成的透镜组成_Some,因此_pageNumber i将是棱镜。

现在,如果您使用视图作为棱镜会发生什么?zero值表示失败,例如,选项的零值为 None,但此处未指定零值。

Brian是对的,因为错误消息具有误导性,更好的错误是"不要在棱镜上使用视图",而是尝试获取一个裸值(不在选项内),这可以表示zero失败。

TL;博士

请改用:

preview (Book._pageNumber 1) rayuela // Some { Contents = "The End" }

有人应该发送 PR 以将该行添加到文档中。

相关内容

  • 没有找到相关文章

最新更新