我知道这不是最好的解释但我已经尽力了。
我正在努力理解haskell中变量和函数的位置,其中包含where
关键字和函数中的函数类型的代码。
以这段代码为例。
dummy :: Num a => a -> a -> a -> a
dummy v e = dum
where
dum a@x = v + e + a
我认为第一个函数是简单地在里面执行的,存储变量v和e。用dum执行主体,其中存储了a@x,执行主体做加法。
下面的代码应该采用有序列表并在正确的位置插入值。
如果我用insert' 6 [5, 7, 8]
,我想6 == x和6 == [x],但是如果foldr需要一个起始值,那么它是如何工作的呢?因为第三个代码块显示了这个过程。老师说[6]
是起始值,但是我似乎不能用列表作为foldr的起始值。
总结一下:有两个输入,它们在函数体中的位置。以及foldr在这里是如何工作的。
第一次
2条答案
按热度按时间3phpmpom1#
我将一步一步地对你的例子进行评估:
insert' 6 [5, 7, 8]
等效于(insert' 6) [5, 7, 8]
,因为函数应用程序关联到左侧。根据
insert'
的定义,insert' 6
等于foldr insx [6]
,其中x
=6
。这就是所谓的 * eta-约简 *,以lambda演算中的“eta规则”命名,基本上它的意思是,如果你有一个函数,它可以这样写:
其中
g
是某个表达式,如果g
不包含x
,则可以将其简化为f = g
,因为f
只是沿着其参数直接传递给g
。例如:因此,
Int -> Int -> Int
类型的“双参数”定义也可视为单参数定义(返回单参数函数Int -> (Int -> Int)
)或零参数定义(一个变量),它是一个“双参数”函数(Int -> Int -> Int)
。关键是 * 所有函数实际上只有一个参数 *,我们只是有一些多参数函数链的语法糖。所以你的例子中的整个表达式等于
(foldr insx [6]) [5, 7, 8]
。因为函数应用是左结合的,括号是多余的,所以这和foldr insx [6] [5, 7, 8]
是一样的。所以foldr
在这里是完全应用的。foldr的评估然后扩展为以下内容:
你可以扩展
insx
的定义,使其适用于每一种参数组合,我将从最右边的insx
调用开始,即insx 8 [6]
,它在列表语法上等价于insx 8 (6:[])
。根据定义,第一个守卫是,因此结果是
z:y:zs
=6:8:[]
=[6, 8]
。最右边的调用
insx 7 [6, 8]
设置y
=7
,ys
=[6, 8]
,z
=6
,以及zs
=[8]
。守护函数的值为6 == 6 && 6 < 7
,这也是真的,给出6:7:[8]
=[6, 7, 8]
。最后我们得到
insx 5 [6, 7, 8]
。现在y
=5
,ys
=[6, 7, 8]
,z
=6
,以及zs
=[7, 8]
。保护函数是6 == 6 && 6 < 5
,它是 false,所以我们继续下一个保护函数。otherwise
总是true,所以我们返回y:ys
=5:[6, 7, 8]
=[5, 6, 7, 8]
。注意我们总是有
z == x
;作为一个练习,试着通过一个示例输入,其中条件的这一部分在计算过程中的某个点评估为假。您可以使用任何类型的值作为
foldr
的“accumulator”参数,在本例中它是一个列表。具体来说,foldr
具有以下类型:专门指定为
t
=[]
,因为 input 是一个列表,即:在你的例子中,它被进一步特殊化为
b
=[a]
,因为 output 也是一个相同类型的列表:a -> [a] -> [a]
参数用insx
填充,初始累加器是[x]
=[6]
,结果是函数[a] -> [a]
,然后将其应用于输入[5, 7, 8]
。并且由于类型类约束,a
可以是集合Num
和Ord
中的任何类型。例如X1 M80 N1 X或X1 M81 N1 X。ldfqzlk82#
TDD和逐步细化可用于理解此程序的作用,如下所示: