我正在编写一个函数,用于从Haskell的列表中过滤第一个合格值。
我尝试了基于过滤器功能的功能,但是我不知道该功能如何运行。
所以我为每种情况添加了跟踪。
filter' :: (a -> Bool) -> [a] -> [a]
filter' p (x:xs) | p x = trace "{1}" x : (filter' p xs)
| otherwise = trace "{2}" filter' p xs
filter' p [] = []
filterFirst :: (a->Bool) -> [a]->[a]
filterFirst p xs = case (trace "{3}" (filter' p xs)) of
(x : xs) -> trace "{4}" [x]
otherwise -> trace "{5}" []
测试时:
filterFirst even [2,2]
{3}
{4}
[{1}
2]
filterFirst even [1,2]
{3}
{2}
{4}
[{1}
2]
filterFirst even [1,1,2]
{3}
{2}
{2}
{4}
[{1}
2]
结果[2]
是正确的,但是执行顺序已连接。
case of
知道何时测试(x : xs)
? case of
如何准确执行?答案 0 :(得分:3)
trace "{1}" x : (filter' p xs)
解析为
(trace "{1}" x) : (filter' p xs)
类似地,
trace "{2}" filter' p xs
解析为
(trace "{2}" filter') p xs
如果需要其他解释,则需要分别编写trace "{1}" (x : (filter' p xs))
和trace "{2}" (filter' p xs)
。
我不确定您的问题3。 {3}为什么要执行多次?它不是循环/递归的一部分。
让我们逐步评估
filterFirst even [2,2]
解释器要打印结果,所以我们必须计算结果。
我们输入filterFirst
的定义(始终首先对表达式的外部部分求值),
case (trace "{3}" (filter' p xs)) of
(x : xs) -> trace "{4}" [x]
otherwise -> trace "{5}" []
where
p = even
xs = [2,2]
在这里我们需要做出决定。 case
需要知道要评估的分支,因此需要知道要匹配的模式(x : xs
或otherwise
)。因此,它要做的第一件事就是评估我们正在分析的表达式:
trace "{3}" (filter' p xs)
where
p = even
xs = [2,2]
最外面的表达式是对trace
的调用,该调用现在显示{3}
并移交给
filter' p xs
where
p = even
xs = [2,2]
现在最外面的表达式是对filter'
的调用,该调用定义为
filter' p (x:xs) | p x = trace "{1}" x : (filter' p xs)
| otherwise = trace "{2}" filter' p xs
filter' p [] = []
我们必须再次做出决定:我们使用哪个方程式?选择取决于第二个参数的值,因此这会触发对xs = [2,2]
(最外层)的求值。好吧,这里没有什么有趣的事情,因为[2,2]
已经得到了充分评估。
[2,2]
是2 : (2 : [])
的语法糖,因此它与第一个等式绑定绑定
p = even
x = 2
xs = 2 : [] -- same as [2]
我们现在必须评估模式背后的警卫:
p x
even 2
True
成功!我们的返回值为trace "{1}" x : (filter' p xs)
,(如上所述)是(:)
对两个参数trace "{1}" x
和filter' p xs
的应用。
这里没有进一步的评估。回想一下,我们仍在尝试评估
case ... of
(x : xs) -> trace "{4}" [x]
otherwise -> trace "{5}" []
因此,我们只关心列表的最外面的构造函数是:
还是[]
,现在知道它是:
。我们选择第一个分支,它产生
trace "{4}" [x]
where
x = trace "{1}" x_inner
xs = filter' p xs_inner
x_inner = 2
xs_inner = 2 : []
p = even
这有点令人困惑,因为您已将所有变量命名为x
和xs
。如果我们内联所有我们已经知道其值的变量,则绑定将减少为:
trace "{4}" [x]
where
x = trace "{1}" 2
xs = filter' even (2 : [])
xs
完全不使用,x
仅使用一次,因此它实际上等同于
trace "{4}" [trace "{1}" 2]
首先评估{4}
(来自trace
),然后得出结果
[trace "{1}" 2]
-- syntactic sugar for
(trace "{1}" 2) : []
列表打印代码在这里开始工作:我们已经有了至少一个元素的列表,因此它输出[
(列表的开始)。要打印第一个元素本身,我们需要对其进行评估:
trace "{1}" 2
这最终将打印{1}
并产生2
,这将使列表打印代码输出2
和]
(对于列表的末尾)。
就是这样!
答案 1 :(得分:0)
我没有检查所有内容,但请注意
trace "{1}" x : (filter' p xs)
表示
(trace "{1}" x) : (filter' p xs)
因此,{1}
将在您访问第一个元素内容时打印,而不是仅在生成它时打印。我想你想要
trace "{1}" (x : (filter' p xs))
我也将{2}
行改写为
trace "{2}" (filter' p xs)