【问题标题】:How to write the related functions for this GHC type families example?如何为这个 GHC 类型族示例编写相关函数?
【发布时间】:2016-02-16 14:41:05
【问题描述】:

GHC/Type families 网页上,它有半个入门示例说明类型族为何有用。

data family XList a
data instance XList Char = XCons !Char !(XList Char) | XNil
data instance XList () = XListUnit !Int

基本上,它表示Char 的列表可以由 cons 单元格表示。 () 的列表除了它的长度之外没有任何有用的信息,所以我们可以用它的长度来表示列表。

那太好了。那么这个列表的其余实现呢。 length 将如何定义,!!fromList 将如何定义?

【问题讨论】:

    标签: haskell ghc type-families


    【解决方案1】:

    对于XList Char,它可能是:

    {-# LANGUAGE TypeFamilies #-}
    import Prelude hiding ((!!), length)
    import qualified Prelude
    
    class XList' a where
        data family XList a :: *
        fromList :: [a] -> XList a
        length   :: XList a -> Int
        (!!)     :: XList a -> Int -> a
    
    instance XList' Char where
        data XList Char = XCons !Char !(XList Char) | XNil
    
        fromList []     = XNil
        fromList (x:xs) = XCons x (fromList xs)
    
        length XNil         = 0
        length (XCons x xs) = 1 + length xs
    
        XNil         !! _ = error "index error!"
        (XCons x xs) !! 0 = x
        (XCons x xs) !! k = xs !! (k - 1)
    

    然后:

    \> let a = fromList "wxyz"
    \> :t a
    a :: XList Char
    \> length a
    4
    \> a !! 2
    'y'
    

    XList () 类似:

    instance XList' () where
        data XList () = XListUnit !Int
    
        fromList a = XListUnit $ Prelude.length a
        length (XListUnit n) = n
    
        (XListUnit n) !! k
            | k < 0 || n <= k = error "index error!"
            | otherwise       = ()
    

    【讨论】:

    • 谢谢。该网页以独立版本开始,而不是与类型类相关联。您能否说明如何定义独立版本?
    • “关联”类型和数据系列差别很小。它们实际上并没有以任何方式“关联”,如果您实现类而不是系列,编译器会向您发出警告(您也可以为关联类型和数据系列设置默认值)。如果将 XList 移出类,这里唯一的区别是语法:data XList .. where ... 变为 data instance XList ... where ... 并移出实例声明。
    【解决方案2】:

    只是一个小附录:

    您可以将XList a 保留为非类型类关联的类型族,只需为保存操作的XList-y 类型添加一个类型类;例如:

    {-# LANGUAGE TypeFamilies #-}
    
    -- Original definition from your question
    data family XList a
    data instance XList Char = XCons !Char !(XList Char) | XNil
    data instance XList () = XListUnit !Int
    
    -- New class for XList-y types
    class XListy a where
        length :: XList a -> Int
        (!!) :: XList a -> Int -> a
        fromList :: [a] -> XList a
    
    instance XListy () where
        length (XListUnit n) = n
        _ !! _ = ()
        fromList xs = XListUnit $ Prelude.length xs
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-19
      • 1970-01-01
      • 1970-01-01
      • 2018-10-04
      相关资源
      最近更新 更多