在hugomg的回答,我们有
data RecList a
= Elem a
| Dim [RecList a]
deriving (Eq, Show)
这些并不完全代表某些n的n维列表;事实上,它们允许混合不同维度的列表,如Dim [Elem 0, Dim [Elem 0]]
。在仙人掌的答案中,我们有一个更复杂的类型,通过在类型级别暴露维度并强制所有列表具有该维度来修复此问题;但它使用了一些非常复杂的扩展。
在这个答案中,我们将给出一个没有混合维度列表的类型,但它不需要扩展。这个想法仅仅是通过给更高维度的列表提供更多的构造函数来跟踪维度。所以:
data DeepList a = Z a | S (DeepList [a]) deriving Show
每个值将是一个Peano nat给出的维度,后面是该维度的列表。因此:
Z 0
S (Z [0])
S (S (Z [[0]]))
都是值。另一方面,我们根本不能写类似
S (S (Z ["zero", ["zero"]]))
因为它不是很好的类型!
我们可以构造这种类型的值。为了测试目的,我将使用replicate 3
而不是repeat
,但这个想法是相同的。
makeList :: Int -> a -> DeepList a
makeList 0 v = S (Z (replicate 3 v))
makeList n v = S (makeList (n-1) (replicate 3 v))
在ghci的:
*Main> makeList 2 5
S (S (S (Z [[[5,5,5],[5,5,5],[5,5,5]],[[5,5,5],[5,5,5],[5,5,5]],[[5,5,5],[5,5,5],[5,5,5]]])))
一旦我们都给予了Functor
实例DeepList
,这不是太难写你的索引列表,或者:
instance Functor DeepList where
fmap f (Z v) = Z (f v)
fmap f (S v) = S (fmap (map f) v)
nD :: Int -> DeepList [Int]
nD 0 = Z []
nD n = S (fmap (\v -> map (:v) [0..]) (nD (n-1)))
在ghci中:
*Main> putStrLn . take 100 . show $ nD 3
S (S (S (Z [[[[0,0,0],[1,0,0],[2,0,0],[3,0,0],[4,0,0],[5,0,0],[6,0,0],[7,0,0],[8,0,0],[9,0,0],[10,0,
*Main> let S (S (S (Z v))) = nD 3
*Main> putStrLn . take 100 . show . drop 1 $ v
[[[[0,0,1],[1,0,1],[2,0,1],[3,0,1],[4,0,1],[5,0,1],[6,0,1],[7,0,1],[8,0,1],[9,0,1],[10,0,1],[11,0,1]
*Main> putStrLn . take 100 . show . map (drop 1) $ v
[[[[0,1,0],[1,1,0],[2,1,0],[3,1,0],[4,1,0],[5,1,0],[6,1,0],[7,1,0],[8,1,0],[9,1,0],[10,1,0],[11,1,0]
*Main> putStrLn . take 100 . show . map (map (drop 1)) $ v
[[[[1,0,0],[2,0,0],[3,0,0],[4,0,0],[5,0,0],[6,0,0],[7,0,0],[8,0,0],[9,0,0],[10,0,0],[11,0,0],[12,0,0
这是两个问题在一个...第二个有一些简单的解决方案,我相信你会发现启发,但第一个,如果可以解决的话,很可能会涉及一些大型的基于单身的框架与许多类型级编程。你确定你不想把你的问题分成两个吗? – Cactus
@Cactus我对'type-level'编程非常感兴趣,请你帮我分解这个问题,因为我对haskell很陌生,不能分辨两者之间的区别吗? –