13

我是 Haskell 的绝对新手,但我试图了解它是如何工作的。

我想编写自己的惰性整数列表,例如 [1,2,3,4,5...]。

对于我写的列表

ones = 1 : ones

尝试后,效果很好:

*Main> take 10 ones
[1,1,1,1,1,1,1,1,1,1]

我怎样才能为增加整数做同样的事情?

我已经尝试过了,但它确实失败了:

int  = 1 : head[ int + 1]

在那之后,我怎样才能制作一个将两个流相乘的方法?如:

mulstream s1 s2 = head[s1] * head[s2] : mulstream [tail s1] [tail s2]
4

5 回答 5

21

int = 1 : head [ int + 1]不起作用的原因是:

  • head 返回单个元素,但 to 的第二个参数:需要是一个列表。
  • int + 1尝试添加一个列表和一个数字,这是不可能的。

创建从 1 到无穷大的列表的最简单方法是[1..]

要计算除 1 以外的步数,您可以使用[firstElement, secondElement ..],例如创建所有正奇数的列表: [1, 3 ..]

要获得[x, f x, f (f x), f (f (f x)),...]可以使用的形式的无限列表iterate f x,例如iterate (*2) 1将返回列表[1, 2, 4, 16,...]

要对两个列表的每一对元素成对应用操作,请使用 zipWith:

mulstream s1 s2 = zipWith (*) s1 s2

为了使这个定义更简洁,您可以使用无点形式:

mulstream = zipWith (*)
于 2010-03-21T13:08:12.453 回答
21

对于自然数,您必须使用 map:

num1 = 1 : map (+1) num1

或理解:

num2 = 1 : [x+1 | x <- num2]

或者当然:

num3 = [1..]
于 2010-03-21T13:14:31.783 回答
5

我不确定这是否是您要问的,但在我看来,您想建立一个增加自然数的列表,而不依赖任何其他列表。所以,通过这个令牌,你可以做类似的事情

incr a = a : inrc (a+1)
lst = inrc 1

take 3 lst
=> [1,2,3]

从技术上讲,这被称为累加函数(我相信),然后我们所做的就是使其特殊情况易于与 ' lst'一起使用

您可以从那里发疯,执行以下操作:

lst = 1 : incr lst where incr a = (head a) + 1 : incr (tail a)

take 3 lst
=> [1,2,3]

等等,虽然这可能依赖于一些你还没有学过的东西(在哪里)——从 OP 来看——但它仍然应该很容易阅读。

哦,对了,然后是列表乘法。好吧,你可以zipWith (*)像上面提到的那样使用,或者你可以像这样重新发明轮子(这更有趣,相信我:)

lmul a b = (head a * head b) : lmul (tail a) (tail b) 
safemul a b  
  | null a || null b  =  []
  | otherwise
         = (head a * head b) : safemul (tail a) (tail b)

的原因safemul,我相信,你可以通过试验函数找到lmul,但它与 ' tail' (和 ' head' 也是如此)有关。问题是,在 中没有空列表、不匹配列表等情况lmul,因此您要么必须将各种定义 ( lmul _ [] = []) 拼凑在一起,要么使用守卫和 orwhere等​​等......或者坚持使用zipWith: )

于 2010-03-21T14:54:06.590 回答
4

语言中有这样的语法:

take 10 [1,2..]

=> [1,2,3,4,5,6,7,8,9,10]

你甚至可以做不同的步伐:

take 10 [1,3..]
=> [1,3,5,7,9,11,13,15,17,19]
于 2010-03-21T14:38:56.917 回答
0

您可以定义一个不超过一定数量的列表,然后通过保持前者不变(依此类推)将第一个与第二个相加,如下所示:

naturals :: Integer -> [Integer]
naturals n
  | n <= 0    = []
  | otherwise = nat n []
    where
      nat 1 a = (1:a)
      nat n a = nat (n-k) (nat k a)
        where
          k = (n-1)

sumOf :: [Integer] -> [Integer]
sumOf l = sof l []
  where
    sof [] a = a
    sof (x:[]) a = (x:a)
    sof (x:y:zs) a = sof (x:a) (sof ((x+y):zs) a)

由于它们都是一,因此您可以通过更改它们总和的顺序以任何您喜欢的方式递增它们,从左到右,到中间点等等。您可以使用以下方法测试最多一百个(或更多):

(sumOf . naturals) 100

编辑:为了复杂,请阅读 Will Ness 下面的评论。

于 2021-10-23T23:20:13.633 回答