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