在Haskell中将List的各种长度转换为Tuple

时间:2011-05-02 18:22:45

标签: list haskell tuples

我想将转换列表[[1,2,3],[2,3]]转换为元组[(1,2,3),(2,3)]

我的职能:

thr [a,b,c] = (a,b,c)
tupel [] = []
tupel (x:xs) = if length x==3 then thr x:(tupel xs) else (tupel xs)

这项工作有三个要素。

thr [a,b,c] = (a,b,c)
two [a,b]   = (a,b)
tupel [] = []
tupel (x:xs) = if length x==3 then thr x:(tupel xs) else two x:(tupel xs)

为什么不这样做?

错误:在应用程序中键入错误 *表达式:两个x:tupel2 xs 术语:两个x 类型:(a,a) * 不符合:(a,a,a)

2 个答案:

答案 0 :(得分:6)

好的,让我们跳到最后并启动ghci。 [(1,2,3),(1,2)]有哪些类型?

ghci> :t [(1,2,3),(1,2)]

<interactive>:1:10:
     Couldn't match expected type `(t0, t1, t2)'
                 with actual type `(t3, t4)'
     In the expression: (1, 2)
     In the expression: [(1, 2, 3), (1, 2)]
     In an equation for `it': it = [(1, 2, 3), (1, 2)]

该错误不是因为我输入数据错误,而是因为[(1,2,3),(1,2)]无效haskell。

haskell中的列表可以包含无限数量的项目,但需要注意的是所有项目必须属于同一类型。

这可能看起来很奇怪,但(1,2,3)(1,2)的类型不同。一个是3元组,一个是2元组。

元组与列表相反 - 它只能容纳特定数量的项目,但它们可以是一堆不同的类型。元组类型由它们包含的项目给出的类型序列定义。

因此,3个整数的元组(或者,如ghc将显示的,类似数字的东西)与2个整数的元组不同。我们可以使用ghci中的:t运算符直接看到这一点:

ghci> :t (1,2,3)
(1,2,3) :: (Num t1, Num t2, Num t) => (t, t1, t2)
ghci> :t (1,2)
(1,2) :: (Num t1, Num t) => (t, t1)

请注意(2,3,4)(2,3)的类型分别与(1,2,3)(1,2)匹配:

ghci> :t (2,3,4)
(2,3,4) :: (Num t1, Num t2, Num t) => (t, t1, t2)
ghci> :t (2,3)
(2,3) :: (Num t1, Num t) => (t, t1)

这是因为(2,3,4)(1,2,3)是两个具有相同类型的值。 (1,2)(2,3)也是如此。

因此,在haskell中没有将[[1,2,3],[1,2]]转换为[(1,2,3),(1,2)]的函数,因为这样的函数的结果无法进行类型检查。

答案 1 :(得分:4)

元组有不同的类型,因此没有单一(简单)类型可以提供给tupel函数。

但是,通过退回并使用 sum类型,您可以对要返回的所有变体进行编码:

data T a
    = One   a
    | Two   a a
    | Three a a a
    deriving Show

two :: [a] -> T a
two [a,b]   = Two   a b

thr :: [a] -> T a
thr [a,b,c] = Three a b c

tuple :: [[a]] -> [T a]
tuple []           = []
tuple ([a,b]  :xs) = Two   a b   : tuple xs
tuple ([a,b,c]:xs) = Three a b c : tuple xs
tuple (_ : xs)     =               tuple xs

注意我们如何通过模式匹配来区分两元素和三元素列表。

其次,优良作法是记下每个函数的预期类型 - 这将有助于解决设计中的混淆,并快速揭示逻辑错误,如两种不同的元组类型。

运行它,你可以看到它如何很好地分组:

*Main> tuple [[1,2,3],[2,3]] 
[Three 1 2 3,Two 2 3]