【问题标题】:Creating tuples variations from a list - Haskell从列表创建元组变体 - Haskell
【发布时间】:2014-02-12 01:26:40
【问题描述】:

我是一个相对的 haskell 新手,我正在尝试使用我命名为 splits 的等式创建一个元组列表,该等式最初来自一个列表,如下所示:

splits [1..4] --> [ ([1],[2,3,4]), ([1,2],[3,4]), ([1,2,3],[4]) ]

splits "xyz" --> [ ("x","yz"), ("xy","z") ]

创建一个包含 1、2、3 个元素等的元组列表。我想我可能应该使用 take/drop 函数,但这是我目前所拥有的,我遇到了很多类型声明错误...有什么想法吗?

splits :: (Num a) => [a] -> [([a], [a])]

splits [] = error "shortList"

splits [x]
       | length [x] <= 1 = error "shortList"
       | otherwise = splits' [x] 1
         where splits' [x] n = [(take n [x], drop n [x])] + splits' [x] (n+1)

【问题讨论】:

  • 正如你所声明的,第一个参数的类型是一个列表。但是你不需要函数本身的类型,除非你是模式匹配,而只是参数名称。换句话说,尝试将“[x]”替换为参数名称“x”,我们知道它是一个列表。 (在这种情况下,“[x]”表示一个包含一个元素 x 的列表)
  • 即使我尝试上述方法,我也会收到类型错误:“无法从上下文( Num a) 由 splits 的类型签名绑定 :: Num a => [a] -> [([a], [a])] at splits.hs:4:10-39 可能的修复:为(Num [([a], [a])]) 在表达式中: splits' x 1" 而且我不相信我必须以这种方式定义 splits',我也不确定如何。
  • 这个“无法推断”错误是因为您试图将[(take n [x], drop n [x])]splits' [x] (n+1) 一起“添加”,这实际上没有任何意义。
  • 在最后一行中,您使用运算符“+”,它是为 Num 或某些此类类型保留的。想想哪个运算符可以更好地组合返回类型。
  • 哦,哇,这就是我所需要的?哈哈它完美地工作!非常感谢,我想我很容易出现这样的新手错误。 :)

标签: list haskell tuples


【解决方案1】:

Haskell-y 方法是使用来自Data.Listinitstails 函数:

inits [1,2,3,4] = [ [],        [1],     [1,2], [1,2,3], [1,2,3,4] ]
tails [1,2,3,4] = [ [1,2,3,4], [2,3,4], [3,4], [4],     [] ]

然后我们将这两个列表压缩在一起并删除第一对:

splits xs = tail $ zip (inits xs) (tails xs)

或等效地,首先删除每个组成列表的第一个元素:

          = zip (tail (inits xs)) (tail (tails xs))

【讨论】:

    【解决方案2】:
    splits [] = []
    splits [_] = []
    splits (x:xs) = ([x], xs) : map (\(ys, zs) -> (x:ys, zs)) (splits xs)
    

    【讨论】:

      【解决方案3】:

      你有几个错误。

      a 不需要有 Num a 类。

      使用[][x] 作为模式,但不是变量,请改用xs

      使用++ 代替+ 来连接列表。

      在我们的例子中,使用(:) 将列表添加到值而不是++

      添加停止递归,如附加变量maxnsplits'

      splits :: [a] -> [([a], [a])]
      splits [] = error "shortList"
      splits xs
             | lxs <= 1 = error "shortList"
             | otherwise = splits' xs 1 lxs
               where
                 lxs = length xs
                 splits' xs n maxn 
                     | n > maxn  = []
                     | otherwise = (take n xs, drop n xs) : splits' xs (n+1) maxn
      

      【讨论】:

        【解决方案4】:

        有一个内置函数可以完成您想要的部分功能:

        splitAt :: Int -> [a] -> ([a], [a])
        

        它做了它看起来会做的事情:

        > splitAt 2 [1..4]
        ([1,2],[3,4])
        

        使用这个函数,你可以像这样定义分割:

        splits xs = map (flip splitAt xs) [1..length xs - 1]
        

        【讨论】:

          猜你喜欢
          • 2020-06-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-21
          • 2017-03-21
          • 1970-01-01
          相关资源
          最近更新 更多