Name conflicts in Haskell records

前端 未结 3 1503
生来不讨喜
生来不讨喜 2020-12-08 04:41

Haskell doesn\'t have dot notation for record members. For each record member a compiler creates a function with the same name with a type RecType -> FieldType. This leads

3条回答
  •  挽巷
    挽巷 (楼主)
    2020-12-08 05:24

    Another way to avoid this problem is to use the lens package. It provides a makeFields template haskell function, which you can use like this:

    {-# LANGUAGE FlexibleInstances      #-}
    {-# LANGUAGE FunctionalDependencies #-}
    {-# LANGUAGE MultiParamTypeClasses  #-}
    {-# LANGUAGE TemplateHaskell        #-}
    {-# LANGUAGE TypeSynonymInstances   #-}
    import           Control.Lens
    
    data A = A
      { _aText :: String
      }
    makeFields ''A   -- Creates a lens x for each record accessor with the name _aX
    
    data B = B
      { _bText  :: Int
      , _bValue :: Int
      }
    -- Creates a lens x for each record accessor with the name _bX
    makeFields ''B  
    
    main = do
      let a = A "hello"
      let b = B 42 1
    
      -- (^.) is a function of lens which accesses a field (text) of some value (a)
      putStrLn $ "Text of a: " ++ a ^. text 
      putStrLn $ "Text of b: " ++ show (b ^. text)
    

    If you don't want to use TemplateHaskell and lens, you can also do manually what lens automates using TemplateHaskell:

    {-# LANGUAGE FlexibleInstances      #-}
    {-# LANGUAGE FunctionalDependencies #-}
    {-# LANGUAGE MultiParamTypeClasses  #-}
    {-# LANGUAGE TypeSynonymInstances   #-}
    data A = A
      { aText :: String
      }
    
    data B = B
      { bText  :: Int
      , bValue :: Int
      }
    
    -- A class for types a that have a "text" field of type t
    class HasText a t | a -> t where
    
      -- An accessor for the text value
      text :: a -> t
    
    -- Make our two types instances of those
    instance HasText A String where text = aText
    instance HasText B Int where text = bText
    
    main = do
      let a = A "hello"
      let b = B 42 1
      putStrLn $ "Text of a: " ++ text a
      putStrLn $ "Text of b: " ++ show (text b)
    

    But I can really recommend learning lens, as it also provides lots of other utilities, like modifying or setting a field.

提交回复
热议问题