haskell - 如何为 sum 类型编写镜头

标签 haskell haskell-lens

我有这样的类型:

data Problem =
   ProblemFoo Foo |
   ProblemBar Bar |
   ProblemBaz Baz
Foo , BarBaz他们的名字都有一个镜头:
fooName :: Lens' Foo String
barName :: Lens' Bar String
bazName :: Lens' Baz String
现在我想创建一个镜头
problemName :: Lens' Problem String
显然我可以使用 lens 来写这个。构造函数和一对case语句,但有更好的方法吗?
outside 的文档谈到使用 Prism 作为一种一流的模式,这听起来很有启发性,但我不知道如何真正实现它。
(编辑:添加 Baz 案例,因为我的真正问题与 Either 不是同构的。)

最佳答案

你是对的,你可以用 outside 写它.首先,一些定义:

{-# LANGUAGE TemplateHaskell #-}

import Control.Lens

newtype Foo = Foo { _fooName :: String }
    deriving (Eq, Ord, Show)
makeLenses ''Foo

newtype Bar = Bar { _barName :: String }
    deriving (Eq, Ord, Show)
makeLenses ''Bar

newtype Baz = Baz { _bazName :: String }
    deriving (Eq, Ord, Show)
makeLenses ''Baz

data Problem =
    ProblemFoo Foo |
    ProblemBar Bar |
    ProblemBaz Baz
    deriving (Eq, Ord, Show)
makePrisms ''Problem

以上就是您在问题中描述的内容,除了我也在为 Problem 制作棱镜.
outside的类型(为了清楚起见,专门针对功能、简单的透镜和简单的棱镜)是:
outside :: Prism' s a -> Lens' (s -> r) (a -> r)

给定一个棱镜,例如sum 类型的情况,outside让您了解 sum 类型的函数,该函数针对处理案例的函数分支。指定函数的所有分支相当于处理所有情况:
problemName :: Problem -> String
problemName = error "Unhandled case in problemName"
    & outside _ProblemFoo .~ view fooName
    & outside _ProblemBar .~ view barName
    & outside _ProblemBaz .~ view bazName

这相当漂亮,除了需要添加 error由于缺乏合理的违约情况。 The total library只要您愿意进一步扭曲您的类型,就可以提供一种替代方案,并在此基础上进行详尽的检查:
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric #-}

import Control.Lens
import GHC.Generics (Generic)
import Lens.Family.Total    

-- etc.

-- This is needed for total's exhaustiveness check.
data Problem_ a b c =
    ProblemFoo a |
    ProblemBar b |
    ProblemBaz c
    deriving (Generic, Eq, Ord, Show)
makePrisms ''Problem_

instance (Empty a, Empty b, Empty c) => Empty (Problem_ a b c)

type Problem = Problem_ Foo Bar Baz

problemName :: Problem -> String
problemName = _case
    & on _ProblemFoo (view fooName)
    & on _ProblemBar (view barName)
    & on _ProblemBaz (view bazName)

关于haskell - 如何为 sum 类型编写镜头,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52832649/

相关文章:

c - FFI 导入的 MPI 常量的 GHCi 链接器错误(通过 c2hs)

haskell - 将 Lens' a b 转换为 Lens' a(也许是 b)

list - 嵌套函数应用

haskell - 将值列表插入具有持久性的数据库中

Haskell 使用一级透镜来创建复杂透镜

Haskell 透镜 setter/getter ,比较两个透镜 setter/getter 的值

haskell - 无法使用镜头从嵌套 JSON 收集值

haskell - 如何获得具有重载字段名称的经典镜头?

haskell - 为什么这个递归函数没有被优化? ( haskell )

haskell - 从 runDb 捕获异常