嵌套的块在Haskell中?

时间:2015-05-31 03:12:08

标签: 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,4], 3, 2) == [[[1,1,1],[2,2,2]],[[3,3,3],[4,4,4]]]

但在哈斯克尔,我不能说

nestedChunksOf :: [Int] -> [a] -> [[a]]

nestedChunksOf :: [Int] -> [a] -> [[[a]]]

那么如何在Haskell中实现相同的目标呢?

4 个答案:

答案 0 :(得分:12)

nestedChunksOf这样的函数不能直接在Haskell中完成,至少不能在正常列表上运行。列表的深度是类型的一部分,因此您不能具有参数指定的任意深度。

可以做的是嵌套chunksOf

如果我们这样定义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]]]

我希望能达到你想要的效果!

答案 1 :(得分:6)

如其他答案中所述,这不能像在Haskell中那样直接完成,您总是需要知道表达式的类型,从而区分[a][[a]]等。 ,使用polymorphic recursion,您可以通过在构造函数中包装每个级别来定义允许这种任意嵌套的数据类型:

data NestedList a = Value a | Nested (NestedList [a])
  deriving (Show)

所以只有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)

确实

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]]])))

答案 2 :(得分:5)

使用依赖类型可以很容易地完成。

我们想表示[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 (S Z)) [] 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]]]

答案 3 :(得分:2)

这在Haskell中通过" normal"无法实现。意味着因为它需要一个依赖类型 - 结果的类型取决于第一个参数的长度。

也许一个元组解决方案是可以接受的?

{-# 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.