Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Haskell'中记录选择器;s型类_Haskell_Types_Record_Typeclass - Fatal编程技术网

在Haskell'中记录选择器;s型类

在Haskell'中记录选择器;s型类,haskell,types,record,typeclass,Haskell,Types,Record,Typeclass,我想用很少的默认方法实现一个类型类,但是我得到了一个错误,我不能在类型类定义中使用记录选择器 下面的代码基本上创建了type类,该类定义了add函数,该函数应该向一些数据类型的repr记录中添加一个元素。代码如下: import qualified Data.Graph.Inductive as DG class Graph gr a b where empty :: DG.Gr a b empty = DG.empty repr :: gr -> DG

我想用很少的默认方法实现一个
类型类
,但是我得到了一个错误,我不能在
类型类
定义中使用
记录选择器

下面的代码基本上创建了
type类
,该类定义了
add
函数,该函数应该向一些
数据类型
repr
记录中添加一个元素。代码如下:

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中声明这样的方法吗

澄清

我需要这样的设计,因为我有一些
数据类型
,它们的行为类似。比如说,我们得到了
A
B
C
数据类型。它们中的每一个都应该有一个记录
repr::DG.Gr a b
,其中
a
b
对于
a
b
C
都是不同的

A
B
C
共享相同的功能,如
add
delete
(基本上添加或删除元素以记录
repr
)。如果这些数据类型共享许多函数,那么实现
类型类中的函数并创建该
类型类的实例是有意义的-这些函数将自动为每个
数据类型实现

另外,在调用
add
函数时,我希望其中一些
数据类型
(假设我希望
B
)的行为稍有不同。当为
B
创建
类型类的
实例时,很容易实现此行为

  • 记录更新语法

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

    如果某些数据类型
    A
    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}
    

    也可以在此处使用:


    您可以尝试类似的方法(使用元组列表作为示例,而不是
    DG


    答案是“不”,但“某种程度上,使用镜头”,但更重要的是,我觉得人们对这里的课程有一个根本性的误解。如果你说你为什么想上这样一门课,那会很有帮助;我们或许可以提出一个更为惯用的替代方案。@DanielWagner-我已经为我试图解决的问题添加了一个说明-我希望现在还不太清楚,我为什么要这样做:)请参阅我的最新答案。在第二个示例中,我使用执行实际更新的
    update
    方法(可以在实例中使用记录更新语法实现),第三个示例使用
    Control.Lens
    @JJJ,我想Lens就是我要找的!非常感谢。
    {-# 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}
    
    {-# 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}
    
    {-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, TypeSynonymInstances #-}
    
    class MyClass g a b | g -> a b where
          extract :: g -> [(a,b)]
          construct :: [(a,b)] -> g 
    
          empty :: g
          empty = construct []
    
          add :: (a,b) -> g  -> g
          add i d = construct $  [i] ++ (extract d) 
    
    data A  = A {reprA :: [(Int,Int)]}
    
    instance MyClass A Int Int  where
             extract = reprA
             construct = A
    
    data B  = B {reprB :: [(String,String)]}
    
    instance MyClass B String String  where
             extract = reprB
             construct = B