在 Haskell 类型类中记录选择器

2024-01-18

我想实施一个Type Class有几个默认方法,但我收到一个错误,我无法使用record selectors inside type classes定义。

下面的代码基本上创建了type class它定义了add函数,它应该添加一个元素到repr记录一些data type。这是代码:

import qualified Data.Graph.Inductive     as DG

class Graph gr a b where
    empty :: DG.Gr a b
    empty = DG.empty

    repr :: gr -> DG.Gr a b

    -- following function declaration does NOT work:
    add :: a -> gr -> gr
    add el g = g{repr = DG.insNode el $ repr g}

编译器抛出错误:

repr is not a record selector
In the expression: g {repr = DG.insNode el $ repr g}
In an equation for add:
    add el g = g {repr = DG.insNode el $ repr g}

是否可以在 Haskell 中声明此类方法?

澄清

我需要这样的设计,因为我有一些data types,其行为方式类似。比方说,我们有A, B and C data types。每个人都应该有一个记录repr :: DG.Gr a b, where a and b每个都是不同的A, B and C.

A, B and C共享相同的功能,例如add or delete(基本上添加或删除要记录的元素repr)。如果这些数据类型共享许多功能,那么在以下位置实现这些功能是有意义的:type class并举例说明这一点type class- 这些功能将针对我们的每个人实施data type自动地。

另外我会喜欢其中一些data types(假设我想要B) 调用时的行为略有不同add其上发挥作用。在制作时很容易实现这种行为instance of the type class for B.


  1. 记录更新语法

     <record-instance> { <record-field-name> = ..., ... }
    

    工作时<record-instance>是一个实例/术语known代数数据类型(因此<record-field-name>它是已知字段吗),在您的代码中它只是一些(临时)多态参数gr,所以你需要先转换gr to Gr,然后更新它,然后...

  2. 我觉得gr and Gr在某种意义上应该是等价的,即我们需要一个反函数repr, say iface,能够实施add.

这是一个例子:

{-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances, FlexibleInstances #-}

data Gr a b = Gr { _internal :: [(a, b)] } deriving ( Show, Read )

class Graph gr a b where

  repr :: gr -> Gr a b
  iface :: Gr a b -> gr

  -- iface . repr == id {gr}
  -- repr . iface == id {Gr a b}

  -- add element via "interface" (get a representation via @repr@, update it, and then 
  -- return an interface back with @iface@)
  add :: (a, b) -> gr -> gr
  add el g = let r = repr g in iface r { _internal = el : _internal r }
  -- or
  add el = iface . insNode el . repr where
    insNode x (Gr xs) = Gr (x : xs) -- or whatever

instance Graph String Int Int where
  repr = read
  iface = show

test :: String
test = add (1 :: Int, 2 :: Int) "Gr { _internal = [] }"
-- test => "Gr {_internal = [(1,2)]}"

如果某些数据类型A and B 总计的 Gr a b(这样我们就不能写出逆矩阵repr),那么我们可以这样做:

{-# LANGUAGE MultiParamTypeClasses #-}

data Gr a b = Gr [(a, b)] deriving ( Show )

class Graph gr a b where

  repr :: gr -> Gr a b

  update :: gr -> (Gr a b -> Gr a b) -> gr
  -- 2: update :: gr -> Gr a b -> gr

  add :: (a, b) -> gr -> gr
  add el g = update g $ insNode el
    -- 2: update g (insNode el $ repr g)
    where insNode x (Gr xs) = Gr (x : xs)

data A = A { _aRepr :: Gr Char Char, _aRest :: Char } deriving ( Show )
data B = B { _bRepr :: Gr Int Int, _bRest :: Int } deriving ( Show )

instance Graph A Char Char where
  repr = _aRepr
  update r f = r { _aRepr = f $ _aRepr r }
  -- 2: update r g = r { _aRepr = g }

instance Graph B Int Int where
  repr = _bRepr
  update r f = r { _bRepr = f $ _bRepr r }
  -- 2: update r g = r { _bRepr = g }

testA :: A
testA = add ('1', '2') $ A (Gr []) '0'
-- => A {_aRepr = Gr [('1','2')], _aRest = '0'}

testB :: B
testB = add (1 :: Int, 2 :: Int) $ B (Gr []) 0
-- => B {_bRepr = Gr [(1,2)], _bRest = 0}

也可以使用lenses http://hackage.haskell.org/package/lens here:

{-# LANGUAGE MultiParamTypeClasses, TemplateHaskell #-}

import Control.Lens

data Gr a b = Gr [(a, b)] deriving ( Show )

insNode :: (a, b) -> Gr a b -> Gr a b
insNode x (Gr xs) = Gr (x : xs)

class Graph gr a b where
  reprLens :: Simple Lens gr (Gr a b)

add :: Graph gr a b => (a, b) -> gr -> gr
add el = reprLens %~ insNode el

data A = A { _aRepr :: Gr Char Char, _aRest :: Char } deriving ( Show )
data B = B { _bRepr :: Gr Int Int, _bRest :: Int } deriving ( Show )

makeLenses ''A
makeLenses ''B

instance Graph A Char Char where
  reprLens = aRepr

instance Graph B Int Int where
  reprLens = bRepr

main :: IO ()
main = do
  let a = A (Gr []) '0'
      b = B (Gr []) 0
  print $ add ('0', '1') a
  print $ add (0 :: Int, 1 :: Int) b
-- A {_aRepr = Gr [('0','1')], _aRest = '0'}
-- B {_bRepr = Gr [(0,1)], _bRest = 0}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Haskell 类型类中记录选择器 的相关文章

随机推荐

  • 如何防止(引导)固定顶部导航在移动设备上缩放

    在使用Bootstrap 3的固定顶部导航时 我注意到当用户在移动设备上使用原生缩放时 顶部导航也变得非常大 这会导致非常糟糕的用户体验 导航模糊了大部分内容并最终自行损坏 如以下示例所示 这个问题可以在网上看到http www explo
  • 如何暂停 android.speech.tts.TextToSpeech?

    我正在使用 Android TTS 播放文本 android speech tts TextToSpeech I use TextToSpeech speak说话和 stop停止 有没有办法也暂停文本 据我所知 TTS SDK 没有任何暂停
  • 如何仅修改react .map函数中的一个元素?

    我对反应有点陌生 并且对在这里做什么有点迷失 我正在从 firebase 加载数据并使用 map 函数渲染该对象的 props 以列出页面上的所有 评论 效果很好 我还想调用一个组件 该组件允许用户回复单个评论 即地图中的一个特定元素 但正
  • JPA:从属性创建 EntityManagerFactory

    我在 JAR 项目中使用 JPA 并使用 persistence xml 来设置我的 EntityManager 但由于 persistence xml 在构建后位于 JAR 内 因此用户随后更改设置非常复杂 因此 我正在寻找一种解决方案
  • C语言中数字之间插入空格

    我该如何获取像这样的数字123456并将其打印为1 2 3 4 5 6 最简单的方法 尽管不是最快的 可能是首先sprintf http linux die net man 3 sprintf将数字存入字符串缓冲区 然后循环遍历该缓冲区pr
  • 如何在 sbt 中有条件地调用任务?

    Say taskA是一项繁重的任务 只有在启用它并且taskAEnabled是对应的设置键 一个天真的方法是 val taskAConditional Def task taskAEnabled taskA map taskAEnabled
  • 为什么我的交叉表在 Excel 中被切断?

    我正在尝试使用 BIRT 创建 Excel 电子表格 该电子表格是将两个对象映射在一起的交叉表 行数和列数是根据 MySQL 数据库中的值动态变化的 目前我已经实现了 PDF 输出报告 现在 我正在尝试创建 Excel 报告的第二个版本 我
  • 使用 Rails 3.1.0 和 ubuntu 安装 Nokogiri 1.5.0 时出错

    这是在服务器上运行捆绑安装供应商 宝石时出现的错误 Installing nokogiri 1 5 0 with native extensions Gem Installer ExtensionBuildError ERROR Faile
  • 如何防止maven检查外部存储库?

    当我使用 Maven 构建时 我看到它检查所有类型的外部存储库中是否有只有我的本地构建应该生成的工件 我如何告诉它 com myorg 组只能在本地存储库中找到 基本上我想做 m2eclipse 对工作空间分辨率所做的事情 但在命令行上 I
  • 以编程方式更改导航标题

    我有一个带有标题的导航栏 当我双击文本对其进行重命名时 它实际上说它是一个导航项 所以可能就是这样 我正在尝试使用代码更改文本 例如 declare navigation bar as navagationbar here button s
  • 将多个 OSGi 包打包在同一个 jar 中

    我对 OSGi 平台非常陌生 拥有 OSGi 捆绑包B1依赖于另一个包B2 这很可能不是由容器提供的 我可以将两个包打包在同一个包中吗jar 如果是 该怎么做 如果jar已安装并且捆绑包已安装 是的 你可以这样做 有点 通常 OSGi 包是
  • 使用 AngularJS ui-grid $scope.saveRow 保存行数据

    我正在开发一个小型前端应用程序 它将在用户界面网格中显示各种产品运输数据 我有以下代码 HTML p row name works at row company p
  • 向 C# 添加“lazy”关键字时出现的问题

    我很想写这样的代码 class Zebra public lazy int StripeCount get return ExpensiveCountingMethodThatReallyOnlyNeedsToBeRunOnce 编辑 为什
  • 同时从多个线程使用同一个 FluxSink 是否安全

    我认识一个Publisher不得同时发布 但如果我使用Flux create FluxSink 我可以安全地打电话吗FluxSink next同时 换句话说 Spring 是否具有内部魔力来确保事件的正确串行发布 即使FluxSink ne
  • 注意:未定义偏移:2 如何解决?

    我在第 11 行和第 12 行遇到了未定义的 offset 2 错误 这是第 6 15 行的代码 if isset POST submit surveyID POST surveyCategory for i 0 i
  • GDI+ 通用错误 ASP.NET MVC

    我遇到了 GDI 通用错误我已经尝试了每个人所说的方法 即确保包含正在读取的图像文件的文件夹 如下所示 public ImageResult ProfileAsset string profile int width int height
  • 如何处理 Last.FM 或 Wikipedia 等社区 URL 样式?

    我试图理解我应该如何与角色一起工作URLs 这是因为我正在构建一个网站 用户可以在其中存储内容并通过在URL 所以 像Wikipedia or Last FM网站 我在网站上看到 用户可以写类似的内容http it wikipedia or
  • 我必须使用哪个 Windows 注册表项来安装 Delphi Expert?

    我需要为 Delphi IDE 专家创建一个安装程序 所以我找到了这两个注册表项 HKEY CURRENT USER Software Embarcadero BDS x 0 Known IDE Packages HKEY CURRENT
  • pd.read_html() 导入列表而不是数据框

    I used pd read html 从网页导入表格 但 Python 不是将数据构建为数据帧 而是将其导入为列表 如何将数据导入为数据框 谢谢你 代码如下 import pandas as pd import html5lib url
  • 在 Haskell 类型类中记录选择器

    我想实施一个Type Class有几个默认方法 但我收到一个错误 我无法使用record selectors inside type classes定义 下面的代码基本上创建了type class它定义了add函数 它应该添加一个元素到re