如何为具有类型族的记录制作镜头 [英] How to make lenses for records with type-families

查看:86
本文介绍了如何为具有类型族的记录制作镜头的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我所拥有的,尚未编译:

Here's what I've got, which is not compiling:

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}

import Data.Text as T
import Data.Int (Int64)
import Control.Lens

type family Incoming validationResult baseType
type instance Incoming Validated baseType = baseType
type instance Incoming ValidationErrors baseType = Either [T.Text] baseType

data Validated
data ValidationErrors

data Tag = Tag {unTag :: T.Text} deriving (Eq, Show)

data NewTag f = NewTag
  {
    ntClientId :: Incoming f Int64
  , ntTag :: Incoming f Tag
  }

$(makeLensesWith abbreviatedFields ''NewTag)

编译错误:

27   3 error           error:
 • Illegal type synonym family application in instance:
     Incoming f_a1Kvx Int64
 • In the instance declaration for
     ‘HasClientId (NewTag f_a1Kvx) (Incoming f_a1Kvx Int64)’ (intero)
27   3 error           error:
 • Illegal type synonym family application in instance:
     Incoming f_a1Kvx Tag
 • In the instance declaration for
     ‘HasTag (NewTag f_a1Kvx) (Incoming f_a1Kvx Tag)’ (intero)

推荐答案

此处的问题是makeLensesFor将尝试生成实例,如下所示:

The problem here is that makeLensesFor will try to generate an instance as follows:

instance HasClientId (NewTag f) (Incoming f Int64) where
  ....

但是,这是一个错误,因为您无法为类型族应用程序的结果创建实例.为避免这种情况,我们可以为f的两个可能选择中的每一个手动编写实例:

This, however, is an error because you cannot create an instance for the result of a type family application. To avoid this, we can write the instance manually for each of the two possible choices for f:

-- generate lenses _foo for each record selector foo
-- (in this case, generates _ntClientId and _ntTag lenses)
makeLensesWith (lensRules & lensField .~ mappingNamer (\x -> ['_' : x])) ''NewTag

class HasClientId s a | s -> a where
  clientId :: Lens' s a

instance HasClientId (NewTag Validated) Int64 where
  clientId = _ntClientId

instance HasClientId (NewTag ValidationErrors) (Either [T.Text] Int64) where
  clientId f a = f (ntClientId a) <&> \ntClientId' -> a { ntClientId = ntClientId' }

class HasTag s a | s -> a where
  tag :: Lens' s a

instance HasTag (NewTag Validated) Tag where
  tag = _ntTag

instance HasTag (NewTag ValidationErrors) (Either [T.Text] Tag) where
  tag = _ntTag

这篇关于如何为具有类型族的记录制作镜头的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆