【问题标题】:Where clause in haskell function without parameters没有参数的haskell函数中的where子句
【发布时间】:2019-07-01 21:52:56
【问题描述】:
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. 在没有任何参数的情况下,第二行中的substituteOne如何工作?
  2. 我们在哪里提供一个列表作为输入?或者我们在哪里说明我们如何处理该列表?我的意思是编译和执行它可以工作,但不知何故我看不到它
  3. 什么是 x' ?它从来没有在任何地方定义,我们只是以某种方式开始使用它(也许也指问题 1)
  4. map 需要一个函数和一个列表,它才能工作。这里我们有地图功能_。可能指的是 2.,但是替代项 x' 的输出是什么?

如果需要,结果如下所示:

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

【问题讨论】:

    标签: haskell recursion functional-programming


    【解决方案1】:

    (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 生成的列表中。

    【讨论】:

      【解决方案2】:

      substitute1 接受一个参数x'|= 字符之间的位是保护条件。由于这个特定的函数只有一个条件,你可以这样重写它:

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

      因为在where子句中substitute1也可以访问主函数的参数xy

      【讨论】:

        【解决方案3】:

        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 返回的合适值。

        【讨论】:

          猜你喜欢
          • 2019-03-22
          • 2013-12-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-09-04
          • 2015-08-17
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多