Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 是否有一个好的策略使一个功能成为生产功能?_Haskell - Fatal编程技术网

Haskell 是否有一个好的策略使一个功能成为生产功能?

Haskell 是否有一个好的策略使一个功能成为生产功能?,haskell,Haskell,编辑:我在这里所说的“懒惰”似乎不是“懒惰”的意思。我不确定正确的术语是什么。有些人说我正在寻找的术语是“生产性的”,但在这种情况下,我找不到该术语的任何定义。我想要的是一个可以处理无限列表的函数。我会用我对“懒惰”这个词的最好理解,把“懒惰”变成“富有成效” 功能 f a = a:(f (a-1)) h a = h (a ++ (map (-1) a)) 以高效的方式生成无限列表。因为a:在所有其他评估之前 这意味着你可以做取10(f0)就可以了 然而,功能 f a = a:(f (a-1

编辑:我在这里所说的“懒惰”似乎不是“懒惰”的意思。我不确定正确的术语是什么。有些人说我正在寻找的术语是“生产性的”,但在这种情况下,我找不到该术语的任何定义。我想要的是一个可以处理无限列表的函数。我会用我对“懒惰”这个词的最好理解,把“懒惰”变成“富有成效”

功能

f a = a:(f (a-1))
h a = h (a ++ (map (-1) a))
以高效的方式生成无限列表。因为
a:
在所有其他评估之前

这意味着你可以做
取10(f0)
就可以了

然而,功能

f a = a:(f (a-1))
h a = h (a ++ (map (-1) a))
没有生产力,永远不会终止。因为
a++
在另一个计算中。 因此,您无法执行
头(h[0])
,即使它显然是0

是否有一个通用的策略可以将非生产性功能转变为生产性功能

具体来说,我试图解决的问题是,在懒散地使用其第二个参数的同时,使以下内容富有成效:

binarily a [] = a
binarily a (b:bs) = binarily (a ++ map (b+) a) bs

“一般策略”是定义函数,以便在递归之前计算结果值的一部分

f
中,最上面的表达式是
(:)
函数的应用程序,它的第二个参数不严格。这意味着它甚至不需要计算
f(a-1)
。如果您不需要列表的其余部分

h
中,函数做的第一件事是递归-即它不会产生“部分结果”

您的
二进制
函数实际上是“懒惰的”:它的第一个参数不严格,所以

take 10 $ binarily [1..] [1..5]

终止。

h
生成一个增长序列。在
[0]
上,例如:

[0] ++
[0, -1] ++
[0, -1, -1, -2] ++
[0, -1, -1, -2, -1, -2, -2, -3] ++ ...
请注意,它显示了模式
[x,fx,f(fx),…]
——在每一步中,您都要计算函数的一次迭代。这正是
iterate::(a->a)->a->[a]
的目的,而
++
s的折叠正是
concat

h = concat . iterate go
  where go x = x ++ map (subtract 1) x
下面是一个使用相同原理的二进制实现:

binarily a bs
  = concatMap fst
  . takeWhile (not . null . snd)
  $ iterate go (a, bs)
  where
  go (acc, b : bs) = (acc ++ map (b +) acc, bs)
  go x = x
我们迭代函数并从流
中提取
元素,而
snd
)不是
。null
-如果它是无限的,那么它只需要整个流,然后我们
concat
中间累加器(
map fst


您会注意到,如果没有
takeWhile
,您将得到一系列无限重复的元组,其中
snd
[]
。因此,我们所做的是流式处理,直到到达一个固定点,即将递归(
fix
)转换为流式处理

你所寻找的恰当术语是高效,而不仅仅是“懒惰”

head(h[10])
根本没有定义。还原顺序为:
h[10]=>h[10,9]=>h[10,9,9,8]=>h[10,9,9,8,7]=>…
。诚然,这个内部序列的头部总是相同的,
10
,但缩减本身从未停止过。不,它与
F10=>[10,9,8,7,…
不同

你的职能,

binarily a [] = a
binarily a (b:bs) = binarily (a ++ map (b+) a) bs
{-  try it out with [b1,b2,b3,b4] :
a                          b1     the arguments received;
a1@(a  ++ (map (b1+) a))   b2     if we've already produced a, we just need 
                                       to produce  (map (b1+) a)  next
a2@(a1 ++ (map (b2+) a1))  b3     if we've already produced a1, we just need 
                                       to produce  (map (b2+) a1)  next
a3@(a2 ++ (map (b3+) a2))  b4     ai@... name the interim values
a4@(a3 ++ (map (b4+) a3))  []     a4 is returned  -}
相当于

import Data.List (mapAccumL)

-- mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])

binarily a bs = (last . snd) (mapAccumL g a bs)
 where
   g a b = let anew = a ++ map (b+) a
           in (anew, anew)             -- (next_accum, part_result)
mapAccumL
同时捕获累积和生成部分完整结果的模式。列表
:[y]
(其返回值的
snd
字段)是惰性地生成的,从所有的
y
生成,因为它们是由step函数返回的,该函数在列表
:[x]
(您的
(b:bs)
)中为每个
x
调用。因此,只要我们忽略结果的
fst
字段中的最终累积值,该函数也可以无限输入

显然,下一个结果的一部分出现在上一个结果中,可以立即返回:

binarily a bs = a ++ (concat . snd) (mapAccumL g a bs)
 where
   g a b = let                     -- for each b in bs:
               res = map (b+) a    --    this part of the result
               anew = a ++ res     --    next accumulator value
           in (anew, res) 
还有一种可能更“具体”的方法,将您的懒惰/高效的
以二进制方式编写:

binarily a l = a ++ binRest a l

binRest a [] = []
binRest a (b:bs) = a' ++ binRest (a ++ a') bs
  where
    a' = map (b+) a
编辑:我被要求对我的思维过程进行一些解释。如果我们从
二进制a(b1:b2:b3:…)开始,让我们先看看原始帖子中的
二进制
在每一步中作为其第一个参数传递的内容:

很明显,我们可以立即生成
a++
,然后在下一步
map(b1+)
应用于此,因此@JonPurdy的答案中的直接
concat$iterate…a
似乎应该会起作用。实际上,由于我们查看了
bs
列表,因此
scanl
函数比
iterate
函数更匹配

但如果我们尝试这样做,我们会发现仍然存在不匹配:上面第三步中添加的部分不是第二步中添加到参数的部分的函数,而是第二步中添加到整个参数的函数。
concat$scanl…
不太适合这一点

事实上,第一步生产的零件并不符合所有其他零件的规律

因此,我将其分为两个函数:首先,
二进制地
,它处理第一步中要生成的内容,然后将所有其他步骤传递到
binRest


其次,
binRest
,它将迄今为止生成的所有内容作为第一个参数,并使用它来计算在这一步中生成的内容,然后递归。

您的
h
是惰性的,但它不会终止。没有条件告诉编译器何时停止应用
h
。cf.是的,在第一个ar上它是不严格的gument,但不是第二个。我将编辑OP,使其更清晰。您的代码不会生成所需的输出,但我仍然不太确定您通过什么思维过程来获得此解决方案。scanl不适合,因为它只是累积;mapAccumL