Haskell 用于表示具有0到5个值的列表的类型
我有一个练习,我必须定义一个类型来表示一个具有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 现在,考虑一下如何将其扩展到五个元素。好吧,递归解决
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)