使用GADT的"安全列表"的尾部功能

Sno*_*all 5 haskell gadt

我正在阅读GADT演练并且卡在其中一个练习上.给定的数据结构是:

{-# LANGUAGE GADTs, EmptyDataDecls, KindSignatures #-}
data NotSafe
data Safe
data MarkedList :: * -> * -> * where
    Nil  :: MarkedList t NotSafe
    Cons :: a -> MarkedList a b -> MarkedList a c
Run Code Online (Sandbox Code Playgroud)

练习是实现一个safeTail功能.我希望它的行为类似于tailPrelude中的功能:

safeTail (Cons 'c' (Cons 'a' (Cons 't' Nil))) == Cons 'a' (Cons 't' Nil)
safeTail (Cons 'x' Nil)                       == Nil
safeTail Nil  -- type error (not runtime!)
Run Code Online (Sandbox Code Playgroud)

(我实际上没有定义==,但希望很清楚我的意思)

可以这样做吗?我不完全确定这种类型甚至可能......也许safeTail :: MarkedList a Safe -> MarkedList a NotSafe

Mik*_*kov 7

safeTail如果您稍微更改类型结构,则可以实现:

{-# LANGUAGE GADTs, EmptyDataDecls, KindSignatures #-}

data Safe a
data NotSafe

data MarkedList :: * -> * -> * where
    Nil  :: MarkedList t NotSafe
    Cons :: a -> MarkedList a b -> MarkedList a (Safe b)

safeHead :: MarkedList a (Safe b) -> a
safeHead (Cons h _) = h

safeTail :: MarkedList a (Safe b) -> MarkedList a b
safeTail (Cons _ t) = t
Run Code Online (Sandbox Code Playgroud)

与原来的问题safeTail :: MarkedList a Safe -> MarkedList a b是,b可以是任何类型的-不一定是同一类型,该清单的尾部标有.这通过反映类型级别上的列表结构来修复,该类型级别允许safeTail适当地约束返回类型.

  • 注意:这与编码类型中的长度完全相同,因为此处的索引恰好是自然数的类型. (6认同)
  • 当然,当你这样做时,你可以考虑将`NotSafe`和'Safe`重命名为`Zero`和`Succ`.:-)列表的类型告诉你它的长度是多少,而不仅仅是它的长度是否为0. (4认同)