Haskell替换字符串中字符的更好方法

我做了这个功能

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 符号,但它有效,我想知道这里发生了什么

回答

$运营商应用一个函数的参数。我们可以将您的示例重写为

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])的函数类型
  • 接受两个参数 ( Charand Char) 并返回函数 ( [Char] -> [Char])的函数类型
  • 接受三个参数 ( Char, Char, 和[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(library function) 应用于myFunlist 的所有元素xs,并返回所有结果的列表。这有效地实现了您想要的替换。

但是,没有添加第三个参数,

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

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


回答

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

在 Haskell 中,所有函数都只有一个参数。IndeedChar -> Char -> [Char] -> [Char]是 的缩写Char -> (Char -> ([Char] -> [Char])),因此它是一个接受 aChar然后返回另一个函数的函数。如果我们将该函数与 another 一起应用Char,它会返回一个类型[Char] -> [Char]为将Chars列表映射到s 列表的Char函数,最后如果我们使用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并将其映射到箭头 ( ->)右侧的部分。因此,这意味着它将Char演员映射cbif c == a;否则返回c


以上是Haskell替换字符串中字符的更好方法的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>