Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.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 如何用GHC.Generics替换Data.Generics?_Haskell_Ghc Generics - Fatal编程技术网

Haskell 如何用GHC.Generics替换Data.Generics?

Haskell 如何用GHC.Generics替换Data.Generics?,haskell,ghc-generics,Haskell,Ghc Generics,所以我已经使用syb很长时间了,并且经常有如下功能 friendlyNames :: Data a => a -> a friendlyNames = everywhere (mkT (\(Name x _) -> Name x NameS)) 假设泛型a,那么使用GHC.Generics与此等价的是什么?使用GHC.Generics解决这个问题可能是错误的,但现在您可以这样做了 {-# Language TypeOperators #-} {-# Language Deri

所以我已经使用syb很长时间了,并且经常有如下功能

friendlyNames :: Data a => a -> a
friendlyNames = everywhere (mkT (\(Name x _) -> Name x NameS))

假设泛型a,那么使用GHC.Generics与此等价的是什么?

使用GHC.Generics解决这个问题可能是错误的,但现在您可以这样做了

{-# Language TypeOperators #-}
{-# Language DeriveGeneric #-}
{-# Language DefaultSignatures #-}
{-# Language FlexibleContexts #-}
module Demo where

import GHC.Generics
import Language.Haskell.TH
import Language.Haskell.TH.Syntax

data Record = Record { field0 :: Int, field1 :: Maybe Record, field2 :: Name } deriving Generic

instance FriendlyNames Record -- body omitted and derived with GHC.Generics
instance FriendlyNames a => FriendlyNames (Maybe a)
instance FriendlyNames Int where friendlyNames = id -- no-op

------------------------------------------------------------------------

-- | Class for types that can be made friendly
class FriendlyNames a where
  friendlyNames :: a -> a
  default friendlyNames :: (GFriendlyNames (Rep a), Generic a) => a -> a
  friendlyNames = to . gfriendlyNames . from

-- | Replaces the second component of a name with 'NameS'
instance FriendlyNames Name where
  friendlyNames (Name x _) = Name x NameS

------------------------------------------------------------------------

-- | Class for generic structures that can have names made friendly
class GFriendlyNames f where
  gfriendlyNames :: f p -> f p

-- | Case for metadata (type constructor, data constructor, field selector)
instance GFriendlyNames f => GFriendlyNames (M1 i c f) where
  gfriendlyNames (M1 x) = M1 (gfriendlyNames x)

-- | Case for product types
instance (GFriendlyNames f, GFriendlyNames g) => GFriendlyNames (f :*: g) where
  gfriendlyNames (x :*: y) = gfriendlyNames x :*: gfriendlyNames y

-- | Case for sum types
instance (GFriendlyNames f, GFriendlyNames g) => GFriendlyNames (f :+: g) where
  gfriendlyNames (L1 x) = L1 (gfriendlyNames x)
  gfriendlyNames (R1 y) = R1 (gfriendlyNames y)

-- | Case for datatypes without any data constructors (why not?)
instance GFriendlyNames V1 where
  gfriendlyNames v1 = v1 `seq` error "gfriendlyNames.V1"

-- | Case for datatypes without any fields
instance GFriendlyNames U1 where
  gfriendlyNames U1 = U1

-- | Case for data constructor fields
instance FriendlyNames a => GFriendlyNames (K1 i a) where
  gfriendlyNames (K1 x) = K1 (friendlyNames x)
泛型方法更适合于这样的情况,即这种复杂性可以编写一次并隐藏在库中。虽然SYB方法依赖于运行时检查,但请观察为friendlyNames生成的GHC核心,它使记录值变得友好

-- RHS size: {terms: 14, types: 18, coercions: 0}
recordFriendlyNames
recordFriendlyNames =
  \ w_s63w ->
    case w_s63w of _ { Record ww1_s63z ww2_s63A ww3_s63B ->
    case $recordFriendlyNames ww1_s63z ww2_s63A ww3_s63B
    of _ { (# ww5_s63H, ww6_s63I, ww7_s63J #) ->
    Record ww5_s63H ww6_s63I ww7_s63J
    }
    }

-- RHS size: {terms: 19, types: 19, coercions: 0}
$recordFriendlyNames
$recordFriendlyNames =
  \ ww_s63z ww1_s63A ww2_s63B ->
    (# ww_s63z,
       case ww1_s63A of _ {
         Nothing -> Nothing;
         Just g1_a601 -> Just (recordFriendlyNames g1_a601)
       },
       case ww2_s63B of _ { Name x_a3Z3 ds_d5Z5 -> Name x_a3Z3 NameS } #)

我想答案可能是Data.Generics.Uniplate.Operations。名称和名称的定义在哪里?它们来自Language.Haskell.TH.Syntax-即template-Haskell。对于最近GHC的V1,我会选择gfriendlyNames v=案例v的{}。我认为这更清楚地表达了这一点。这似乎不像syb所做的那样——syb函数将处理任何数据实例,查找嵌入的名称值并修改它们。这个GHC.Generics函数不适用于泛型的任何实例,它只适用于显式声明的FriendlyNames实例。这是如何比传统的typeclass更强大的呢?