【问题标题】:Haskell a better way a replacing a character in a stringHaskell 一种更好的方法来替换字符串中的字符
【发布时间】:2021-05-06 19:10:50
【问题描述】:

我做了这个功能

replace :: Char -> Char -> [Char] -> [Char]
replace _ _ [] = []
replace a b (c:r)
    | a == c = b : replace a b r
    | otherwise = c : replace a b r

当我发现这个时,我正在寻找一种更好的方式来编写它:

replace :: Char -> Char -> [Char] -> [Char]
replace a b  = map $ \c -> if c == a then b else c

甚至没有写第三个参数,我不理解 $ 和 \c 符号,但它有效,我想知道这里发生了什么

【问题讨论】:

    标签: list haskell


    【解决方案1】:

    $ 运算符将函数应用于参数。我们可以将您的示例重写为

    replace :: Char -> Char -> [Char] -> [Char]
    replace a b  = map (\c -> if c == a then b else c)
    

    实际上,Haskellers 经常使用$ 来避免括号。由于其他原因,它很少使用。

    关于\c -> ...:这是一个匿名函数,也称为“lambda”。它代表以c 作为参数并返回... 部分的函数。在您的情况下,该函数接受c 并检查它是否等于a,在这种情况下它返回b,否则它返回c。我们可以在没有 lambda 的情况下重写代码,如下所示:

    replace :: Char -> Char -> [Char] -> [Char]
    replace a b  = map myFun
       where
       myFun :: Char -> Char
       myFun = \c -> if c == a then b else c
    

    或者,将参数c移动到=的左边,如下:

    replace :: Char -> Char -> [Char] -> [Char]
    replace a b  = map myFun
       where
       myFun :: Char -> Char
       myFun c = if c == a then b else c
    

    关于“缺少第三个参数”:Char -> Char -> [Char] -> [Char] 类型可以多种方式读取:

    • 采用一个参数 (Char) 并返回一个函数 (Char -> [Char] -> [Char]) 的函数类型
    • 采用两个参数(CharChar)并返回一个函数([Char] -> [Char])的函数类型
    • 采用三个参数(CharChar[Char])并返回一个列表([Char])的函数类型

    由于柯里化,所有这三种解释都是兼容的。确实,“两个参数”函数

    foo :: A -> B -> B
    foo x y = y
    

    和功能

    foo :: A -> B -> B
    foo x = id              -- id is the identity function B -> B
    

    都是一样的。

    在您的示例中,如果需要,您可以将缺失的参数添加到= 的两侧,如下所示:

    replace :: Char -> Char -> [Char] -> [Char]
    replace a b xs = map myFun xs
       where
       myFun :: Char -> Char
       myFun c = if c == a then b else c
    

    在这个展开的代码中,您可以看到map myFun xs 使用map(库函数)将myFun 应用于列表xs 的所有元素,并返回所有结果的列表。 这有效地实现了您想要的替换。

    但是,不添加第三个参数,

    replace :: Char -> Char -> [Char] -> [Char]
    replace a b = map myFun
       where ...
    

    我们仍然可以将map myFun 解释为将函数myFun :: Char -> Char 转换为函数[Char] -> [Char]。如果我们将其解释为“两个参数”函数,后者确实是 replace 的返回类型。也就是说,replace 'a' 'b' 是函数[Char] -> [Char],它接受一个字符串并将其中的每个'a' 替换为'b'

    【讨论】:

      【解决方案2】:

      甚至没有写第三个参数。 (…)

      在 Haskell 中,所有函数都只有 一个 参数。实际上Char -> Char -> [Char] -> [Char]Char -> (Char -> ([Char] -> [Char])) 的缩写,因此它是一个接受Char 然后返回另一个函数的函数。如果我们将该函数与另一个Char 一起应用,它会返回一个[Char] -> [Char] 类型的函数,该函数会将Chars 列表映射到Chars 列表,最后如果我们用一个列表调用该函数Chars 我们得到了Chars 的列表。

      这意味着如果函数的头部有两个参数,那么map $ \c -> if c == a then b else c应该返回一个函数,就是这样。

      (...) 我看不懂$ (...) 符号。

      ($) :: (a -> b) -> a -> b 函数定义为:

      infixr 0 $
      
      ($) :: (a -> b) -> a -> b
      ($) f x = f x

      因此它是功能应用程序。使用它的原因是因为它具有0 的优先级,因此这意味着例如a $ b x 将被评估为a (b x),而a b x 将被评估为(a b) x。因此这意味着该函数等同于map (\c -> if c == a then b else c)

      我不明白 (...) \c 符号

      这是一个 lambda 表达式。它是一个将变量c 作为输入并将其映射到箭头右侧的部分(->)的函数。因此,这意味着它将Character c 映射到b if c == a;否则返回c

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-10-07
        • 2016-01-19
        • 2018-07-07
        • 1970-01-01
        • 1970-01-01
        • 2021-11-12
        • 1970-01-01
        相关资源
        最近更新 更多