Как использовать FSharpPlus.Lens для указания индекса списка?
Пример кода документации определяет
_pageNumber
с использованием
List._item
, но я не могу найти пример его использования. Я попробовал следующий код, но он выдал ошибку.
view (Book._pageNumber 1) rayuela // error
Как это будет использоваться?
2 ответа
Я вижу то же самое:
Нет перегрузок, соответствующих методу «Ноль».
Проблема вызвана тем,
_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, которое не было учтено в документации. Если вы хотите обойти проблему, вы можете определить себя, и тогда пример будет скомпилирован:
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#+, просто так ведет себя объектив.
Некоторая предыстория: призмы или частичные линзы подобны линзам, которые могут выйти из строя, поэтому в принципе вы не можете использовать
Правила композиции гласят, что результат композиции:
- линза с линзой это линза
- линза с призмой (или наоборот) это призма
- призма с призмой это призма
То есть, как только в цепочке композиции есть призма, результатом будет призма.
В нашем случае имеем
Теперь, что произойдет, если вы используете представление для призмы? Значение представляет собой сбой, например, нулевое значение параметра равно None, но здесь не указано нулевое значение.
Брайан прав в том, что сообщение об ошибке вводит в заблуждение, лучшей ошибкой было бы «не использовать вид через призму», но вместо этого происходит попытка получить голое значение (не внутри параметра), которое может представлять сбои с
тл; ДР
используйте вместо этого:
preview (Book._pageNumber 1) rayuela // Some { Contents = "The End" }
Кто-то должен отправить PR, чтобы добавить эту строку в документы.