简体   繁体   English

嵌套的块在Haskell中?

[英]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 因此,只有Valuea同构, 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM