【问题标题】:Potentially infinite list of tuples in HaskellHaskell中潜在的无限元组列表
【发布时间】:2017-11-29 17:27:35
【问题描述】:

我有一个我无法解决的问题。这是关于除数的后续任务。

第一个是定义一个函数,将数字 k 的所有正除数放入一个列表中

编辑:不小心写了错误的代码(这是当你有一个函数 divisors 和 divisor 时得到的......只是在玩耍,看看列表是如何反应的。) 关于列表中有多个的问题,这里不应该发生这种情况,但它会慢很多。

divisor :: Int -> [Int]
divisor k = divisor' 1 k
 where
  divisor' n k  | n > k = []
              | k `mod` n == 0 = (n:result)
              | otherwise = result
   where result = divisor' (n+1) k

到目前为止一切顺利。

我的以下任务是编写一个返回元组列表的函数(x,xs),其中x 是自然数/= 0xsx 的所有正除数的列表。

应该是这样的:

take 7 trueDivisors 
[(1,[]),(2,[1]),(3,[1]),(4,[1,2]),(5,[1]),(6,[1,2,3]),(7,[1])]

take 到底代表什么?这可能是我的问题,因为我重新阅读了任务。通常函数只被他们的名字调用......试图让trueDivisors k 工作)

我已经尝试了很多,比如使用我的第一个函数来获取元组内部列表中的除数,但没有成功。语法错误超过语法错误。

也许有人可以帮助我,或者给我一个提示。可悲的是,剧本中没有类似的东西。谷歌也不太热衷。

提前致谢!

【问题讨论】:

  • 你想要连接这些片段 (1) 生成一个无限列表 [1,2,3,4,......] (2) 了解如何通过对旧列表的所有元素应用函数来生成新列表 (3)一个给定数字的函数,比如x,返回一个元组(x, divisors x)
  • take 只从列表中获取 n 个元素。所以take 3 [5,4,7,10,2] == [5,4,7]
  • 相关问题,divisors 25返回什么?
  • 你熟悉map函数吗?和/或,使用list comprehensions 语法?列表生成器语法怎么样,例如[2..10]take 5 [2,4..]?你知道searching by types吗?
  • 这不过是寻找素数,因此您最好专注于如何做到最好。

标签: list haskell tuples factors


【解决方案1】:

这里有一个提示。如果你map divisors [1..7],你会得到:

[[1,1],[1,2],[1,3],[1,2,2,4],[1,5],[1,2,3,6],[1,7]]

这些是您要创建的关联列表的第二个组成部分,除了您有一个小错误,除非允许多次返回相同的除数。 (提示:您可以使用filter 编写一个很好的divisors 的单行版本,但快速修复是Data.List.nub。)您想返回:

[(1,[1]),(2,[1,2]),(3,[1,3]),(4,[1,2,4]),...]`

解决这个问题的一个简单方法是编写一个辅助函数makeAssoc :: Int -> (Int, [Int]),然后编写map makeAssoc [1..]。这个函数可以调用divisors

另一个是取[1..](map divisors [1..])这两个列表。第一个具有[Int] 类型,第二个具有[[Int]] 类型,并且您希望结果具有[( Int, [Int] )] 类型。所以在Prelude 中寻找一个函数,它将[a][b] 类型的两个列表压缩到[(a,b)] 对列表中。也就是说,查找类型签名为 [a] -> [b] -> [(a,b)] 的函数,看看它们中的任何一个是否符合您的要求。

如果确定类型看起来很复杂,请不要担心:您可以让 GHC 为您完成!如果你写,

divisorAssocs :: [( Int, [Int] )]
divisorAssocs = map _ is
  where is :: [Int]
        is = [1..]

GHC 会将_ 识别为一个打字孔,并告诉您需要填充什么:

• Found hole: _ :: Int -> (Int, [Int])

同样的,如果你把它写成一个洞:

divisorAssocs :: [( Int, [Int] )]
divisorAssocs = _ is (map divisors is)
  where is :: [Int]
        is = [1..]

给你:

• Found hole: _ :: [Int] -> [[Int]] -> [(Int, [Int])]

【讨论】:

    【解决方案2】:

    在 Haskell 中,有限列表和无限列表之间并没有真正的区别。问题是要求您创建一个名为 trueDivisors 的变量(尽管 Haskell 变量不会变化),其类型为 [(Int, [Int])]

    我们先来看看如何制作一些无限列表

    myFirstInfiniteList :: [Int]
    myFirstInfiniteList = [1..]
    powers :: [Int]
    powers = powers’ 1 where
      powers’ n = n : n * 2
    myThirdInfiniteList :: [(Int,[Int])]
    myThirdInfiniteList = map it [1..] where
      it n = (n, [1..n])
    

    现在 Haskell 不会提前知道一个列表是否是无限的,所以如果你尝试打印一个列表,它将永远持续下去。所以你可以使用take函数返回列表的前n个元素(其中n是第一个参数)

    我想这应该足够你现在自己解决了。

    trueDivisors :: [(Int,[Int])]
    trueDivisors = {- you need to do this -}
    

    【讨论】:

      【解决方案3】:

      如何将数和除数配对?

      一个简单的实现是:

      pair n = (n, divisors n)
      

      剩下的就是将pair映射到无限的自然数序列,并取所需数量的元素

      take 7 $ map pair [1..]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-09-28
        • 1970-01-01
        • 2018-01-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-04
        • 1970-01-01
        相关资源
        最近更新 更多