Answers:
好吧,递归解决方案在Haskell中当然是正常的,实际上是一件好事,但是限制元素的数量却有些棘手。因此,对于该问题的简单解决方案,首先考虑bradm给出的愚蠢但可行的解决方案。
使用递归解决方案时,诀窍是在递归下传递一个“ counter”变量,然后在达到允许的最大值时禁用更多的元素。使用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 :# 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’
为了完整起见,让我添加一个“丑陋”的替代方法,但这是非常基本的。
回想一下,Maybe a
是一种类型,其值是形式的Nothing
或Just x
为一些x :: a
。
因此,通过重新解释上述值,我们可以将其Maybe a
视为“受限列表类型”,其中列表可以具有零个或一个元素。
现在,(a, Maybe a)
只需添加一个元素即可,因此它是“列表类型”,其中列表可以具有一个((x1, Nothing)
)或两个((x1, Just x2)
)元素。
因此,Maybe (a, Maybe a)
是“列表类型”,其中列表可以具有零(Nothing
),一个(Just (x1, Nothing)
)或两个((Just (x1, Just x2)
)元素。
您现在应该能够理解如何继续。让我再次强调,这不是使用方便的解决方案,但无论如何,这是(IMO)很好的练习。
使用Haskell的一些高级功能,我们可以使用类型族来概括以上内容:
type family List (n :: Nat) (a :: Type) :: Type where
List 0 a = ()
List n a = Maybe (a, List (n-1) a)
a
s 。Either () (a, Either () (a, Either () (a, Either () ())))
foldr (.) id (replicate 3 $ ([0] ++) . liftA2 (+) [1]) $ [0] == [0,1,2,3]