简体   繁体   English

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

[英]Type for representing a list with 0 to 5 values

I have an exercise where I have to define a type for representing a list with 0 to 5 values.我有一个练习,我必须定义一个类型来表示具有 0 到 5 个值的列表。 First I thought I could solve this recursively like this:首先,我认为我可以像这样递归地解决这个问题:

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

But I don't think this is the correct approach.但我认为这不是正确的方法。 Can you please give me a food of thought.你能不能给我一个思考的食物。

I won't answer your exercise for you — for exercises, it's better to figure out the answer yourself — but here's a hint which should lead you to the answer: you can define a list with 0 to 2 elements as我不会为你回答你的练习——对于练习,最好自己找出答案——但这里有一个提示可以引导你找到答案:你可以将一个包含 0 到 2 个元素的列表定义为

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

Now, think about how can you extend this to five elements.现在,考虑一下如何将其扩展到五个元素。

Well, a recursive solution is certainly the normal and in fact nice thing in Haskell, but it's a bit tricky to limit the number of elements then.好吧,递归解决方案在 Haskell 中当然是正常的,实际上是一件好事,但是限制元素的数量有点棘手。 So, for a simple solution to the problem, first consider the stupid-but-working one given by bradm.因此,对于问题的简单解决方案,首先考虑 bradm 给出的愚蠢但有效的解决方案。

With the recursive solution, the trick is to pass a “counter” variable down the recursion, and then disable consing more elements when you reach the max allowed.使用递归解决方案,诀窍是在递归中传递一个“计数器”变量,然后在达到允许的最大值时禁用更多元素。 This can be done nicely with a GADT:这可以通过 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)

Then然后

*Main> 0:#1:#2:#Nil :: ListMax 5 Int
0 :# (1 :# (2 :# Nil))

*Main> 0:#1:#2:#3:#4:#5:#6:#Nil :: ListMax 5 Int

<interactive>:13:16: error:
    • Couldn't match type ‘1’ with ‘0’
      Expected type: ListMax 0 Int
        Actual type: ListMax (0 + 1) Int
    • In the second argument of ‘(:#)’, namely ‘5 :# 6 :# Nil’
      In the second argument of ‘(:#)’, namely ‘4 :# 5 :# 6 :# Nil’
      In the second argument of ‘(:#)’, namely ‘3 :# 4 :# 5 :# 6 :# Nil’

For the sake of completeness, let me add an "ugly" alternative approach, which is however rather basic.为了完整起见,让我添加一个“丑陋”的替代方法,但它相当基本。

Recall that Maybe a is a type whose values are of the form Nothing or Just x for some x:: a .回想一下, Maybe a是一种类型,其值的形式为NothingJust x对于某些x:: a

Hence, by reinterpreting the values above, we can regard Maybe a as a "restricted list type" where lists can have either zero or one element.因此,通过重新解释上述值,我们可以将Maybe a视为“受限列表类型”,其中列表可以有零个或一个元素。

Now, (a, Maybe a) simply adds one more element, so it is a "list type" where lists can have one ( (x1, Nothing) ) or two ( (x1, Just x2) ) elements.现在, (a, Maybe a)只是简单地添加了一个元素,因此它是一种“列表类型”,其中列表可以有一个 ( (x1, Nothing) ) 或两个 ( (x1, Just x2) ) 元素。

Therefore, Maybe (a, Maybe a) is a "list type" where lists can have zero ( Nothing ), one ( Just (x1, Nothing) ), or two ( (Just (x1, Just x2) ) elements.因此, Maybe (a, Maybe a)是一种“列表类型”,其中列表可以有零个( Nothing )、一个( Just (x1, Nothing) )或两个( (Just (x1, Just x2) )元素。

You should now be able to understand how to proceed.您现在应该能够理解如何进行。 Let me stress again that this is not a convenient solution to use, but it is (IMO) a nice exercise to understand it anyway.让我再次强调,这不是一个方便使用的解决方案,但它(IMO)无论如何都是一个很好的练习来理解它。


Using some advanced features of Haskell, we can generalize the above using a type family:使用 Haskell 的一些高级特性,我们可以使用类型族来概括上述内容:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM