Haskell 用于表示具有0到5个值的列表的类型

Haskell 用于表示具有0到5个值的列表的类型,haskell,Haskell,我有一个练习,我必须定义一个类型来表示一个具有0到5个值的列表。首先我想我可以像这样递归地解决这个问题: data List a = Nil | Content a (List a) 但我认为这不是正确的方法。你能给我一个想法吗。我不会为你回答你的练习-对于练习,最好自己找出答案-但这里有一个提示,可以引导你找到答案:你可以定义一个包含0到2个元素的列表,如下所示: data List a = None | One a | Two a a 现在,考虑一下如何将其扩展到五个元素。好吧,递归解决

我有一个练习,我必须定义一个类型来表示一个具有0到5个值的列表。首先我想我可以像这样递归地解决这个问题:

data List a = Nil | Content a (List a)

但我认为这不是正确的方法。你能给我一个想法吗。

我不会为你回答你的练习-对于练习,最好自己找出答案-但这里有一个提示,可以引导你找到答案:你可以定义一个包含0到2个元素的列表,如下所示:

data List a = None | One a | Two a a

现在,考虑一下如何将其扩展到五个元素。

好吧,递归解决方案在Haskell中当然是正常的,事实上也是很好的,但是限制元素的数量有点棘手。所以,对于一个简单的解决问题的方法,首先要考虑一下Brad给出的愚蠢的工作。 使用递归解决方案,诀窍是在递归中向下传递一个“计数器”变量,然后在达到允许的最大值时禁用考虑更多元素。这可以通过GADT很好地完成:

{-# LANGUAGE GADTs, DataKinds, KindSignatures, TypeInType, StandaloneDeriving #-}

import Data.Kind
import GHC.TypeLits

infixr 5 :#
data ListMax :: Nat -> Type -> Type where
  Nil :: ListMax n a
  (:#) :: a -> ListMax n a -> ListMax (n+1) a

deriving instance (Show a) => Show (ListMax n a)
然后

*Main>0:#1:#2:#Nil::ListMax 5 Int
0:#(1:#(2:#零))
*Main>0:#1:#2:#3:#4:#5:#6:#Nil::ListMax 5 Int
:13:16:错误:
•无法将类型“1”与“0”匹配
应为类型:ListMax 0 Int
实际类型:ListMax(0+1)Int
•在“(:#)”的第二个参数中,即“5:#6:#Nil”
在“(:#)”的第二个参数中,即“4:#5:#6:#Nil”
在“(:#)”的第二个参数中,即“3:#4:#5:#6:#Nil”

为了完整起见,让我添加一个“丑陋”的替代方法,但它相当基本

回想一下,对于某些
x::a
,a可能是一种类型,其值的形式为
Nothing
Just x

因此,通过重新解释上述值,我们可以将
可能的
视为“受限列表类型”,其中列表可以有零个或一个元素

现在,
(a,可能是a)
只需再添加一个元素,因此它是一种“列表类型”,列表可以有一个(
(x1,无)
)或两个(
(x1,仅x2)
)元素

因此,
Maybe(a,Maybe a)
是一种“列表类型”,其中列表可以有零个(
Nothing
)、一个(
Just(x1,Nothing)
)或两个(
(Just(x1,Just x2)
)元素

现在你应该能够理解如何继续。让我再次强调,这不是一个方便的解决方案,但无论如何,理解它(依我看)是一个很好的练习


使用Haskell的一些高级功能,我们可以使用类型族概括上述内容:

type family List (n :: Nat) (a :: Type) :: Type where
    List 0 a = ()
    List n a = Maybe (a, List (n-1) a)

非常感谢。因为这是一个初学者练习,我认为这是一个更简单的方法。但我也会考虑你的方法。这个答案可以用基于Maybe的最大长度n的列表的类型族进行扩展。@leftaroundabout Done。这对初学者来说可能有点太多了,但我还是添加了它。
中最多有三个
a
s())有趣的类型代数,
foldr(.)id(复制3$([0]++)。liftA2(+)[1])$[0]=[0,1,2,3]
type family List (n :: Nat) (a :: Type) :: Type where
    List 0 a = ()
    List n a = Maybe (a, List (n-1) a)