【问题标题】:Convert various length of List to Tuple in Haskell在 Haskell 中将各种长度的 List 转换为 Tuple
【发布时间】:2011-05-02 18:22:44
【问题描述】:

我想将列表 [[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)

【问题讨论】:

  • 很确定你需要依赖类型才能让这样的东西真正起作用……
  • 依赖类型不是必需的。这只是一个简单的旧代数数据类型问题。
  • @Don 嗯,误读了这个问题。问题是他想要一个异构列表。
  • 没错,它们只是带有(显式或隐式)标签的常规列表。

标签: list haskell tuples


【解决方案1】:

好的,让我们跳到最后并启动 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 个整数的元组(或者 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)] 的函数,因为这样的函数的结果不可能进行类型检查。

【讨论】:

    【解决方案2】:

    元组有不同的类型,因此您的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]
    

    【讨论】:

    • 好的 - 很好,但是我如何将 [Three 1 2 3,Two 2 3] 转换为 [(1,2,3),(1,2)]? :D
    • @corium:不可能:haskell 中的列表是同质的(这意味着列表中的每个元素与任何其他元素具有相同的类型)并且具有不同元素数量的元组具有不同的类型。
    • 这是可能的 func [1,2,3,4,5] --> to [(1,2,3),(4,5)] - take n funktion take 列表,但我需要元组-.-
    • 不能返回元组列表,其中元组具有不同的大小。但是,您可以定义自定义数据类型,例如此答案中的T
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    • 2017-05-28
    • 2017-02-28
    • 2013-03-23
    • 1970-01-01
    相关资源
    最近更新 更多