haskell函数中不带参数的where子句

时间:2019-02-07 17:36:09

标签: haskell recursion functional-programming

substitute':: (Eq a)=> a -> a -> [a] -> [a]
substitute' x y = map substituteOne
                  where
                    substituteOne x' | x == x'   = y
                                     | otherwise = x'

因此,此函数的要点是,它将接受类型a的两个输入和类型a的列表,并将列表[a]中的所有元素从“第一个” a替换为“第二个” a。至少任务描述就是这样。

我已经实现了递归版本,但是还需要带有where子句的函数。

那么这就是解决方案。不知何故我有问题:

  1. 第二行中的replaceOne如何在没有任何参数的情况下工作?
  2. 我们在哪里给出列表作为输入?或我们在哪里声明该列表的用途?我的意思是编译并执行它可以,但是以某种方式我看不到它
  3. x'是什么?从来没有在任何地方定义它,我们只是以某种方式开始使用它(也许也提到问题1)
  4. 地图需要一个函数和一个列表,这样它才能起作用。这里我们有地图功能_。可能指的是2.,但是replaceOne x'的输出是什么?

如果需要,结果如下:

substitute' 5 10 [1, 5, 2, 5, 3, 5]
[1,10,2,10,3,10]

3 个答案:

答案 0 :(得分:3)

  

(1)第二行中的substituteOne如何不带任何参数?
  (2)我们在哪里提供列表作为输入?或者我们在哪里声明该列表的作用?我的意思是编译和执行它是可行的,但是以某种方式我看不到它

参数仍然存在;这是currying在起作用。考虑section of an infix operator (+1),这是partial application的特例。给定一个数字,它将产生一个更大的数字。证人:

λ> :t (+1)
(+1) :: Num a => a -> a

我们可以定义一个函数,通过命名列表来增加列表的所有元素

λ> :t \l -> map (+1) l
\l -> map (+1) l :: Num b => [b] -> [b]

但是由于currying而变得不必要。

λ> :t map (+1)
map (+1) :: Num b => [b] -> [b]
毕竟,这是功能性编程。使用Haskell,我们可以像其他语言操纵字符串一样轻松地操纵函数。

  

(3)x'?它从未在任何地方定义,我们只是以某种方式开始使用它(也许也提到问题1)

但是您要做x'定义为substituteOne的参数!

考虑map的类型:

λ> :t map
map :: (a -> b) -> [a] -> [b]

它的第一个参数是一个参数的函数。为了使您的程序能够进行类型检查,类型必须要对齐。我们可以通过添加可选的类型注释来为substituteOne强调这一点-但必须更加努力(通过启用scoped type variables扩展),因为substituteOne是一个内部函数,引用了外部函数范围

substitute':: forall a. Eq a => a -> a -> [a] -> [a]
substitute' x y = map substituteOne
                  where
                    substituteOne :: a -> a
                    substituteOne x' | x == x'   = y
                                     | otherwise = x'
  

(4) map需要一个函数和一个列表,这样它才能起作用。这里我们有map函数_。是指2。但是substituteOne x'的输出是什么?

在应用程序点使用未命名的参数,就像您的代码对map substituteOne所做的那样,被称为pointfree style。在您的情况下,有两个不可见的“点”或变量名:substituteOne的参数和map的列表参数。

您可能对所有事情都一目了然,如

substitute'' :: Eq a => a -> a -> [a] -> [a]
substitute'' x y l = map (\x' -> if x == x' then y else x') l

但是相比之下,这更混乱了。

substituteOne产生的列表中收集了map产生的值。

答案 1 :(得分:1)

substitute的类型为a -> a -> [a] -> [a],这意味着它接受一个一个参数并返回一个类型为a -> [a] -> [a]的函数。这是因为(->)是右关联的,并且上面的类型等效于a -> (a -> [a] -> [a])

由于函数应用程序是左关联的,因此像substitute x y这样的调用等效于(substitute x) yysubstitute x返回的函数的参数。

当一个人写

substitute x y = ...

的语法糖
substitute = \x -> \y -> ...

此外,由于map substituteOne'的类型为[a] -> [a],因此它是substitute x y返回的合适值。

答案 2 :(得分:0)

substitute1采用参数x'|=字符之间的位是保护条件。由于此特定功能只有一个条件,因此您可以像这样重写它:

substitute1 x' = if x == x' then y else x'

因为它位于where子句中,substitute1也可以访问主函数的参数xy