实现一个字符串的字符在 haskell 中重复特定次数的程序
Implementation of a program in which characters of a string repeated certain times in haskell
这是我作业中的问题,因此很可能会收到提示。
我这学期正在学习 Haskell,我的第一个作业要求我编写一个输入 2 个字符串的函数(string1
和 string2
) 和 returns 由第一个字符串 string1
的(重复)字符组成的字符串,直到创建了与 string2
长度相同的字符串。
我只能使用 Prelude 函数 length
.
例如:取 string1
"Key"
和我的名字 "Ahmed"
作为 string2
函数应该 return "KeyKe"
.
这是我目前得到的:
makeString :: Int -> [a] -> [a]
makeString val (x:xs)
| val > 0 = x : makeString (val-1) xs
| otherwise = x:xs
我没有直接给它两个字符串,而是给它一个整数值(因为我可以稍后用它代替长度),但这给了我一个运行时错误:
*Main> makeString 8 "ahmed"
"ahmed*** Exception: FirstScript.hs: (21,1)-(23,21) : Non-exhaustive patterns in function makeString
我认为它可能会影响我的列表 运行 并成为一个空列表(?)。
不胜感激。
我认为这段代码足以解决您的问题:
extend :: String -> String -> String
extend src dst = extend' src src (length dst)
where
extend' :: String -> String -> Int -> String
extend' _ _ 0 = []
extend' [] src size = extend' src src size
extend' (x:xs) src size = x : extend' xs src (size - 1)
extend'
函数将循环第一个字符串,直到它被消耗然后将再次开始消耗它。
您也可以使用 take
和 cycle
之类的函数来实现它:
repeatString :: String -> String
repeatString x = x ++ repeatString x
firstN :: Int -> String -> String
firstN 0 _ = []
firstN n (x:xs) = x : firstN ( n - 1 ) xs
extend :: String -> String -> String
extend src dst = firstN (length dst) (repeatString src)
或更通用的版本
repeatString :: [a] -> [a]
repeatString x = x ++ repeatString x
firstN :: (Num n, Eq n ) => n -> [a] -> [a]
firstN 0 _ = []
firstN n (x:xs) = x : firstN ( n - 1 ) xs
extend :: [a] -> [b] -> [a]
extend _ [] = error "Empty target"
extend [] _ = error "Empty source"
extend src dst = firstN (length dst) (repeatString src)
能够接受任何类型的列表:
>extend [1,2,3,4] "foo bar"
[1,2,3,4,1,2,3]
正如 Carsten 所说,你应该
- 处理列表为空的情况
- 当您放下第一个元素时,将其推到列表末尾。
- return n 为 0 或更低时的空列表
例如:
makeString :: Int -> [a] -> [a]
makeString _ [] = [] -- makeString 10 "" should return ""
makeString n (x:xs)
| n > 0 = x:makeString (n-1) (xs++[x])
| otherwise = [] -- makeString 0 "key" should return ""
在 ghci 中尝试这个:
>makeString (length "Ahmed") "Key"
"KeyKe"
注:本答案写于literate Haskell。将其保存为 Filename.lhs
并在 GHCi 中尝试。
我认为 length
在这种情况下是 red herring。您可以单独使用递归和模式匹配来解决这个问题,这甚至可以用于 非常长的列表 。但首先是第一件事。
我们的函数应该有什么类型?我们取两个字符串,我们将一遍又一遍地重复第一个字符串,这听起来像 String -> String -> String
。然而,这个 "repeat over and over" 并不是字符串独有的:你可以用每一种列表来做,所以我们选择以下类型:
> repeatFirst :: [a] -> [b] -> [a]
> repeatFirst as bs = go as bs
好的,到目前为止没有发生什么奇怪的事情,对吧?我们根据 go
定义了 repeatFirst
,它仍然缺失。在 go
中,我们要将 bs
的项目与 as
的相应项目交换,因此我们已经知道一个基本情况,即如果 bs
为空会发生什么:
> where go _ [] = []
如果 bs
不为空怎么办?在这种情况下,我们要使用 as
中的正确项。所以我们应该同时遍历两者:
> go (x:xs) (_:ys) = x : go xs ys
我们目前正在处理以下情况:空的第二个参数列表和 non-empty 列表。我们仍然需要处理空的第一个参数列表:
> go [] ys =
在这种情况下应该怎么办?那么,我们需要从 as
重新开始。事实上,这有效:
> go as ys
所有内容都集中在一个地方:
repeatFirst :: [a] -> [b] -> [a]
repeatFirst as bs = go as bs
where go _ [] = []
go (x:xs) (_:ys) = x : go xs ys
go [] ys = go as ys
请注意,如果没有限制,您可以使用 cycle
、zipWith
和 const
:
repeatFirst :: [a] -> [b] -> [a]
repeatFirst = zipWith const . cycle
但这可能是另一个问题。
这是我作业中的问题,因此很可能会收到提示。
我这学期正在学习 Haskell,我的第一个作业要求我编写一个输入 2 个字符串的函数(string1
和 string2
) 和 returns 由第一个字符串 string1
的(重复)字符组成的字符串,直到创建了与 string2
长度相同的字符串。
我只能使用 Prelude 函数 length
.
例如:取 string1
"Key"
和我的名字 "Ahmed"
作为 string2
函数应该 return "KeyKe"
.
这是我目前得到的:
makeString :: Int -> [a] -> [a]
makeString val (x:xs)
| val > 0 = x : makeString (val-1) xs
| otherwise = x:xs
我没有直接给它两个字符串,而是给它一个整数值(因为我可以稍后用它代替长度),但这给了我一个运行时错误:
*Main> makeString 8 "ahmed"
"ahmed*** Exception: FirstScript.hs: (21,1)-(23,21) : Non-exhaustive patterns in function makeString
我认为它可能会影响我的列表 运行 并成为一个空列表(?)。
不胜感激。
我认为这段代码足以解决您的问题:
extend :: String -> String -> String
extend src dst = extend' src src (length dst)
where
extend' :: String -> String -> Int -> String
extend' _ _ 0 = []
extend' [] src size = extend' src src size
extend' (x:xs) src size = x : extend' xs src (size - 1)
extend'
函数将循环第一个字符串,直到它被消耗然后将再次开始消耗它。
您也可以使用 take
和 cycle
之类的函数来实现它:
repeatString :: String -> String
repeatString x = x ++ repeatString x
firstN :: Int -> String -> String
firstN 0 _ = []
firstN n (x:xs) = x : firstN ( n - 1 ) xs
extend :: String -> String -> String
extend src dst = firstN (length dst) (repeatString src)
或更通用的版本
repeatString :: [a] -> [a]
repeatString x = x ++ repeatString x
firstN :: (Num n, Eq n ) => n -> [a] -> [a]
firstN 0 _ = []
firstN n (x:xs) = x : firstN ( n - 1 ) xs
extend :: [a] -> [b] -> [a]
extend _ [] = error "Empty target"
extend [] _ = error "Empty source"
extend src dst = firstN (length dst) (repeatString src)
能够接受任何类型的列表:
>extend [1,2,3,4] "foo bar"
[1,2,3,4,1,2,3]
正如 Carsten 所说,你应该
- 处理列表为空的情况
- 当您放下第一个元素时,将其推到列表末尾。
- return n 为 0 或更低时的空列表
例如:
makeString :: Int -> [a] -> [a]
makeString _ [] = [] -- makeString 10 "" should return ""
makeString n (x:xs)
| n > 0 = x:makeString (n-1) (xs++[x])
| otherwise = [] -- makeString 0 "key" should return ""
在 ghci 中尝试这个:
>makeString (length "Ahmed") "Key"
"KeyKe"
注:本答案写于literate Haskell。将其保存为 Filename.lhs
并在 GHCi 中尝试。
我认为 length
在这种情况下是 red herring。您可以单独使用递归和模式匹配来解决这个问题,这甚至可以用于 非常长的列表 。但首先是第一件事。
我们的函数应该有什么类型?我们取两个字符串,我们将一遍又一遍地重复第一个字符串,这听起来像 String -> String -> String
。然而,这个 "repeat over and over" 并不是字符串独有的:你可以用每一种列表来做,所以我们选择以下类型:
> repeatFirst :: [a] -> [b] -> [a]
> repeatFirst as bs = go as bs
好的,到目前为止没有发生什么奇怪的事情,对吧?我们根据 go
定义了 repeatFirst
,它仍然缺失。在 go
中,我们要将 bs
的项目与 as
的相应项目交换,因此我们已经知道一个基本情况,即如果 bs
为空会发生什么:
> where go _ [] = []
如果 bs
不为空怎么办?在这种情况下,我们要使用 as
中的正确项。所以我们应该同时遍历两者:
> go (x:xs) (_:ys) = x : go xs ys
我们目前正在处理以下情况:空的第二个参数列表和 non-empty 列表。我们仍然需要处理空的第一个参数列表:
> go [] ys =
在这种情况下应该怎么办?那么,我们需要从 as
重新开始。事实上,这有效:
> go as ys
所有内容都集中在一个地方:
repeatFirst :: [a] -> [b] -> [a]
repeatFirst as bs = go as bs
where go _ [] = []
go (x:xs) (_:ys) = x : go xs ys
go [] ys = go as ys
请注意,如果没有限制,您可以使用 cycle
、zipWith
和 const
:
repeatFirst :: [a] -> [b] -> [a]
repeatFirst = zipWith const . cycle
但这可能是另一个问题。