Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
String 交换Haskell字符串中的多对字符_String_Haskell_Replace - Fatal编程技术网

String 交换Haskell字符串中的多对字符

String 交换Haskell字符串中的多对字符,string,haskell,replace,String,Haskell,Replace,我正在尝试编写一个Haskell函数,它接受一组字母对,并在所有字母的字符串中交换这组字母,但是我所想到的感觉很尴尬和不自然 我有 swap a b = map (\x-> if x == a then b else if x == b then a else x) sub n = foldr (.) id (zipWith swap (head <$> splitOn "." n) (last <$> splitOn "." n)) ['A'..'Z'] 及 但

我正在尝试编写一个Haskell函数,它接受一组字母对,并在所有字母的字符串中交换这组字母,但是我所想到的感觉很尴尬和不自然

我有

swap a b = map (\x-> if x == a then b else if x == b then a else x)
sub n = foldr (.) id (zipWith swap (head <$> splitOn "." n) (last <$> splitOn "." n)) ['A'..'Z']

但我是Haskell的新手,我觉得我的方法——特别是我的
swap
helper函数(我只在这里使用)——比它需要的更复杂


有没有更好、更惯用的方法来解决这个问题;尤其是利用我错过的语言功能、内置或库函数的功能?

我在阅读您的代码时注意到了一些事情(我没有尝试重写它)。我的第一个建议涉及分离关注点:

我正在尝试编写一个Haskell函数,它接受一组字母对,并在所有字母的字符串中交换这对字母

这意味着更自然的功能类型是:

sub :: [(Char, Char)] -> String -> String
或者,用于更高效的查找:

sub :: Map Char Char -> String -> String
这比用点对分隔的字符串精确得多。然后,您可以在单独的步骤中生成
Char
s之间的关联:

parseCharPairs :: String -> Map Char Char
理想情况下,您还应该处理无效输入(例如
AB.CDE
)和空输入字符串

my
swap
helper函数(我仅在此处使用)

那么您可能应该在
where
子句中定义它。我还避免使用名称
swap
,因为在
数据中有一个相对常见的函数。Tuple
具有相同的名称(
swapleters
可能是一个不错的选择)


foldr(.)id(fmap f xs)y
foldr f y xs
相同。我几乎可以肯定,这可以用一种更简单的方式重写。

我会把这个问题再细分一点。重要的是要记住,较短的代码不一定是最好的代码。您的实现是有效的,但它太紧凑,我无法快速理解。我推荐更像

import Data.Maybe (mapMaybe)

swap = undefined -- Your current implementation is fine,
                 -- although you could rewrite it using
                 -- a local function instead of a lambda

-- |Parses the swap specification string into a list of
-- of characters to swap as tuples
parseSwap :: String -> [(Char, Char)]
parseSwap = mapMaybe toTuple . splitOn "."
    where
        toTuple (first:second:_) = Just (first, second)
        toTuple _ = Nothing

-- |Takes a list of characters to swap and applies it
-- to a target string
sub :: [(Char, Char)] -> String -> String
sub charsToSwap = foldr (.) id (map (uncurry swap) charsToSwap)
sub
函数等效的是

sub swapSpec = foldr (.) id (map (uncurry swap) $ parseSwap swapSpec)
但对于大多数哈斯凯尔人来说,前者可能更容易理解。您还可以更轻松地对交换规范进行更多转换,将其作为元组列表,使其总体上更强大。实际上,您将交换规范的表示与实际交换解耦。即使对于像这样的小程序,保持松散耦合也是很重要的,这样您就可以在编写大型程序时养成良好的习惯

此实现还避免了重新计算交换规范字符串的
splitOn


(我无法执行此代码,因为我在一台没有安装Haskell的计算机上,如果有人注意到任何错误,请编辑以修复。)在FPComplete中试用,输出匹配@raxacoricofallapatorius.。

将替换列表左折可以缩短代码:

import Data.List
import Data.List.Split

sub = foldl' swap ['A'..'Z'] . splitOn "." . reverse
  where
    swap az [a,b] = map (\x -> if x == a then b else if x == b then a else x) az
如果您不在乎是先交换
EB
还是
RB
,请删除背面

如果要替换而不是交换,请执行以下操作:

import Data.List
import Data.List.Split

replace needle replacement haystack =
    intercalate replacement (splitOn needle haystack)

rep = foldl' replace' ['A'..'Z'] . splitOn "."
    where
        replace' az [a,b] = replace [a] [b] az

注意:由于
Char
Enum
的一个实例,因此您可以将
“ABCDE…”
写成
['A'..'Z']
。这里的上下文主要是关于将由句点分隔的字母对字符串(这是一个约束)转换成一个进行替换的字符串。在这种情况下,拥有一个中间结构(在我看来)是没有帮助的。这是作为方便而提供的(用户)输入步骤的一部分。@raxacoricofallapatorius它可能对最终用户没有帮助,但对作者(即您)肯定有帮助。在较小的函数中进行分解可以更容易地指定、理解和测试代码。对于最终用户,函数组合意味着您可以始终提供
endUserSub=sub。parseCharPairs
一步完成所有操作。如果你认为你的用户不需要中间函数,你甚至不需要从你的模块中导出它们。这有点太离谱了(见我的评论)。@raxacoricofallapatorius在几乎所有的上下文中,你会发现普遍接受的智慧是首先将输入解析成有用的数据结构,然后在另一个步骤中使用它。这是为了将进行解析的代码与进行处理的代码分开,因为通常更容易分别考虑这些问题。另外,请注意我给出的最后一行代码,它显示了如何从
分隔字符串直接转换为执行了交换。它是由更小的
parseSwap
工具和
sub:[(Char,Char)]->String-String
@raxacoricofallapatorius的定义构建而成的。为了方便用户,您仍然只能导出或使用采用swap规范的版本,而不是
[(Char,Char)]
,但在内部,您可以使用任何您想要的表示。这为您提供了实现程序内部的灵活性和能力。另一个例子是,您很少看到解析JSON或XML的代码与使用从JSON或XML文档中获得的值交织在一起,在任何处理之前都有解析步骤。这也更加优雅地突出了逻辑(即配对的作用)。
sub swapSpec = foldr (.) id (map (uncurry swap) $ parseSwap swapSpec)
import Data.List
import Data.List.Split

sub = foldl' swap ['A'..'Z'] . splitOn "." . reverse
  where
    swap az [a,b] = map (\x -> if x == a then b else if x == b then a else x) az
import Data.List
import Data.List.Split

replace needle replacement haystack =
    intercalate replacement (splitOn needle haystack)

rep = foldl' replace' ['A'..'Z'] . splitOn "."
    where
        replace' az [a,b] = replace [a] [b] az