haskell - 如何制作具有类型系列的记录镜头

标签 haskell haskell-lens type-families lenses

这是我得到的,但未编译:

{-# 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 将尝试生成一个实例,如下所示:

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

但是,这是一个错误,因为您无法为类型系列应用程序的结果创建实例。为了避免这种情况,我们可以为 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

关于haskell - 如何制作具有类型系列的记录镜头,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41456869/

相关文章:

performance - 如何在 Haskell 中有效地字节交换二进制数据

performance - 为什么这些定点 cata/ana 态射定义优于递归定义?

haskell - 使用 Attoparsec 时输入不完整的问题

haskell - 压缩遍历

haskell - 函数在类型级别上的模式匹配是可能的,但在值级别上则不行,为什么会出现这种差异?

haskell - 使用类型族时简化类型签名?

file - 如何读取(和解析)文件然后附加到同一个文件而不出现异常?

haskell - 使用镜头库构建复杂的功能

haskell - 是否可以懒惰地获取 Traversable 的所有上下文?

haskell - 单子(monad)-tf : MonadReader instance for MonadState