Как конвертировать между ADT с линзами в purescript? - PullRequest
0 голосов
/ 06 ноября 2018

Это код работающего, но упрощенного примера того, чего я хочу достичь. Я хочу отобразить из одного типа записи обмотки в другой:

import Prelude
import Data.Lens
import Data.String as String

newtype AsString = AsString { names :: Array String }
newtype AsSize   = AsSize   { names :: Array Int }

_names = lens _.names (_ { names = _ })

to_sizes :: AsString -> AsSize
to_sizes (AsString s) = AsSize $ over (_names <<< traversed) String.length s

Как мне сделать то же самое только с объективами и без предварительного развертывания записи?

При использовании объектива типа lens (\(AsString s) -> s) (const AsString) для оригинального типа, я предполагаю, что результат будет оригинального типа?

Ответы [ 2 ]

0 голосов
/ 06 ноября 2018

Я не уверен, что вы будете рады этому ответу, так как я также предлагаю немного рефакторинга здесь ... Если вы недовольны, пожалуйста, дайте мне знать, и я постараюсь предоставить пример кода на основе линз ниже, не касаясь ваших типов; -)

Можете ли вы принять изменения AsString и AsSize следующим образом?

newtype Names a = Names { names :: Array a }

type AsString = Names String
type AsSize = Names Int

Этот рефакторинг немного упростит операции и сделает ваш тип более пригодным для повторного использования. Я действительно рекомендую этот разговор о силе параметров типа: https://www.youtube.com/watch?v=BHjIl81HgfE).

Для поля names мы можем создать линзу, используя общую функцию prop.

Что касается типа Name, мы должны сначала получить экземпляр Newtype (обратите внимание на довольно специфический синтаксис этого вывода - я думаю, что компилятор типа _ выводит сам себя):

 newtype Names a = Names { names :: Array a }
 derive instance newtypeNames ∷ Newtype (Names a) _

Этот класс предоставляет методы wrap и unwrap, которые используются объективом _Newtype. Теперь мы можем просто использовать объектив _Newtype.

Наконец-то вы сможете составить эти два. Вот и мы:

module Main where

import Prelude

import Data.Lens (over, traversed)
import Data.Lens.Iso.Newtype (_Newtype)
import Data.Lens.Record (prop)
import Data.Newtype (class Newtype)
import Data.String as String
import Type.Prelude (SProxy(..))

newtype Names a = Names { names :: Array a }
derive instance newtypeNames ∷ Newtype (Names a) _

type AsString = Names String
type AsSize = Names Int

_names  = prop (SProxy ∷ SProxy "names")

toSizes :: AsString -> AsSize
toSizes = over (_Newtype <<< _names <<< traversed) (String.length)

приписка

Я часто пишу также это, чтобы упростить вывод типов, если я изменяю тот же тип:

_Newtype' ∷ ∀ s a. (Newtype s a) ⇒ Iso' s a
_Newtype' = iso unwrap wrap
0 голосов
/ 06 ноября 2018

Полагаю, я нашел ответ путем экспериментов:

import Prelude
import Data.Lens
import Data.String as String

newtype AsString = AsString { names :: Array String }
newtype AsSize   = AsSize   { names :: Array Int }

_ToSize = lens (\(AsString s) -> s) (const AsSize)
_names  = lens _.names (_ { names = _ })

to_sizes :: AsString -> AsSize
to_sizes s = over (_ToSize <<< _names <<< traversed) String.length s

Кажется, что (const AsSize) "отражает" исходную запись в новый тип.

...