[英]Nested chunksOf in Haskell?
Say I want to do this: 说我想这样做:
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]]]
In Python, I can do this 在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]]]
But in Haskell, I can't just say 但在哈斯克尔,我不能只说
nestedChunksOf :: [Int] -> [a] -> [[a]]
or 要么
nestedChunksOf :: [Int] -> [a] -> [[[a]]]
So how can I achieve the same thing in Haskell? 那么如何才能在Haskell中实现同样的功能呢?
A function like nestedChunksOf
can't be done directly in Haskell, at least not one which operates on normal lists. 像
nestedChunksOf
这样的函数不能直接在Haskell中完成,至少不能在普通列表上运行。 The depth of the list is part of the type, so you can't have an arbitrary depth specified by a parameter. 列表的深度是类型的一部分,因此您不能具有参数指定的任意深度。
But what you can do is nest chunksOf
. 但你可以做的是嵌套
chunksOf
。
If we define chunksOf
like this: 如果我们定义
chunksOf
如下:
chunksOf :: Int -> [a] -> [[a]]
chunksOf _ [] = []
chunksOf n xs = fxs : chunksOf n sxs
where (fxs, sxs) = splitAt n xs
We can then nest it: 我们可以嵌套它:
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]]]
I hope that accomplishes what you wanted! 我希望能完成你想要的!
As stated in the other answers, this can't be done directly as in Haskell you always need to know the type of an expression and thus distinguish between [a]
, [[a]]
etc. However, using polymorphic recursion you can define a data type that allows such arbitrary nesting by wrapping each level in a constructor: 正如其他答案中所述,这不能直接完成,因为在Haskell中你总是需要知道表达式的类型,从而区分
[a]
, [[a]]
等。但是,使用多态递归你可以定义一种数据类型,它允许通过在构造函数中包装每个级别来进行任意嵌套:
data NestedList a = Value a | Nested (NestedList [a])
deriving (Show)
So just Value
is isomorphic to a
, Nested (Value ...)
is isomorphic to [a]
, double Nested
to [[a]]
etc. Then you can implement 因此,只有
Value
与a
同构, Nested (Value ...)
与[a]
同构,双Nested
到[[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)
And indeed 确实如此
print $ nestedChunksOf [3, 2] [1,1,1,2,2,2,3,3,3,4,4,4]
outputs 输出
Nested (Nested (Nested (Value [[[1,1,1],[2,2,2]],[[3,3,3],[4,4,4]]])))
It can be done fairly easily with dependent types. 使用依赖类型可以相当容易地完成。
We'd like to express that the length of the [Int]
argument determines the type of the result. 我们想表示
[Int]
参数的长度决定了结果的类型。 We need two things for that: a list type with fixed length, and a type-level function which computes the return type from the length: 我们需要两件事:一个具有固定长度的列表类型,以及一个从长度计算返回类型的类型级函数:
{-# 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 nfa
applies the type constructor f
n
times to an argument. Iterate nfa
适用类型构造f
n
次争论。 For example, Iterate (S (SZ)) [] Int
reduces to [[Int]]
. 例如,
Iterate (S (SZ)) [] Int
减少为[[Int]]
。 nestedChunksOf
can be written directly now: nestedChunksOf
现在可以直接编写:
nestedChunksOf :: Vec n Int -> [a] -> Iterate (S n) [] a
nestedChunksOf Nil as = as
nestedChunksOf (n :> ns) as = chunksOf n $ nestedChunksOf ns as
Usage: 用法:
> 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]]]
This can not be achieved in Haskell through "normal" means because it would require a dependent type - the type of the result depends on the length of the first argument. 这在Haskell中无法通过“正常”方式实现,因为它需要依赖类型 - 结果的类型取决于第一个参数的长度。
Perhaps a tuple solution would be acceptable? 也许一个元组解决方案是可以接受的?
{-# 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.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.