List Haskell中的嵌套chunksOf?
说我想这样做:List Haskell中的嵌套chunksOf?,list,haskell,nested,List,Haskell,Nested,说我想这样做: nestedChunksOf [3, 2] [1,1,1,2,2,2,3,3,3,4,4,4] == [[[1,1,1], [2,2,2]], [[3,3,3], [4,4,4]]] 在Python中,我可以做到这一点 def group(a, *ns): for n in ns: a = [a[i:i+n] for i in xrange(0, len(a), n)] return a group([1,1,1,2,2,2,3,3,3,4,4
nestedChunksOf [3, 2] [1,1,1,2,2,2,3,3,3,4,4,4] == [[[1,1,1], [2,2,2]], [[3,3,3], [4,4,4]]]
在Python中,我可以做到这一点
def group(a, *ns):
for n in ns:
a = [a[i:i+n] for i in xrange(0, len(a), n)]
return a
group([1,1,1,2,2,2,3,3,3,4,4,4], 3, 2) == [[[1,1,1],[2,2,2]],[[3,3,3],[4,4,4]]]
但在哈斯克尔,我不能只说
nestedChunksOf :: [Int] -> [a] -> [[a]]
或
那么我如何在Haskell中实现同样的功能呢?像
nestedChunksOf
这样的函数不能直接在Haskell中实现,至少不能在普通列表中操作。列表的深度是类型的一部分,因此不能由参数指定任意深度
但您可以做的是嵌套块
如果我们这样定义chunksOf
:
chunksOf :: Int -> [a] -> [[a]]
chunksOf _ [] = []
chunksOf n xs = fxs : chunksOf n sxs
where (fxs, sxs) = splitAt n xs
然后我们可以将其嵌套:
Main> :l test.hs
[1 of 1] Compiling Main ( test.hs, interpreted )
Ok, modules loaded: Main.
*Main> chunksOf 3 [1,1,1,2,2,2,3,3,3,4,4,4]
[[1,1,1],[2,2,2],[3,3,3],[4,4,4]]
*Main> chunksOf 2 $ chunksOf 3 [1,1,1,2,2,2,3,3,3,4,4,4]
[[[1,1,1],[2,2,2]],[[3,3,3],[4,4,4]]]
我希望这能实现你的愿望 这在Haskell中无法通过“正常”方式实现,因为它需要依赖类型-结果的类型取决于第一个参数的长度
也许可以接受元组解决方案
{-# Language TypeFamilies #-}
{-# Language FlexibleInstances #-}
import Data.List.Split
class NestedChunksOf a where
nco :: a -> [b] -> AList a b
type AList a b :: *
instance NestedChunksOf (Int,Int) where
nco (f,s) xs = chunksOf f (chunksOf s xs)
type AList (Int,Int) a = [[[a]]]
-- More instances as desired.
使用依赖类型可以相当容易地完成
我们想表示,[Int]
参数的长度决定了结果的类型。为此,我们需要两件事:具有固定长度的列表类型,以及根据长度计算返回类型的类型级别函数:
{-# LANGUAGE DataKinds, GADTs, TypeFamilies #-}
import Data.List.Split
data Nat = Z | S Nat -- natural numbers (zero, successor)
data Vec n a where -- "n" length lists of "a" elements
Nil :: Vec Z a
(:>) :: a -> Vec n a -> Vec (S n) a
infixr 5 :>
type family Iterate n f a where
Iterate Z f a = a
Iterate (S n) f a = f (Iterate n f a)
Iterate n f a
将类型构造函数f
n
次应用于参数。例如,Iterate(S(sz))[]Int
减少为[[Int]]]
nestedChunksOf
现在可以直接编写:
nestedChunksOf :: Vec n Int -> [a] -> Iterate (S n) [] a
nestedChunksOf Nil as = as
nestedChunksOf (n :> ns) as = chunksOf n $ nestedChunksOf ns as
用法:
> nestedChunksOf (2 :> 3 :> Nil) [1,1,1,2,2,2,3,3,3,4,4,4]
[[[1,1,1],[2,2,2]],[[3,3,3],[4,4,4]]]
正如其他答案中所述,这无法直接完成,因为在Haskell中,您始终需要知道表达式的类型,从而区分[a]
、[[a]]
等。但是,使用可以通过将每个级别包装到构造函数中来定义允许这种任意嵌套的数据类型:
data NestedList a = Value a | Nested (NestedList [a])
deriving (Show)
因此,Value
同构于a
,Nested(Value…
同构于[a]
,doubleNested
同构于[[a]]
等。然后您可以实现
chunksOf :: Int -> [a] -> [[a]]
...
nestedChunksOf :: [Int] -> [a] -> NestedList a
nestedChunksOf [] xs = Nested (Value xs)
nestedChunksOf (c:cs) xs = Nested (nestedChunksOf cs $ chunksOf c xs)
事实上
print $ nestedChunksOf [3, 2] [1,1,1,2,2,2,3,3,3,4,4,4]
输出
Nested (Nested (Nested (Value [[[1,1,1],[2,2,2]],[[3,3,3],[4,4,4]]])))
这太棒了!类型族的奇妙用法。
Nested (Nested (Nested (Value [[[1,1,1],[2,2,2]],[[3,3,3],[4,4,4]]])))