0

这是我作业中的一个问题,因此很可能会受到赞赏。

这个学期我正在学习Haskell,我的第一个作业要求我编写一个函数,该函数输入 2 个字符串 (string1string2) 并返回一个由第一个字符串的(重复的)字符组成的字符串,string1 直到一个与创建的长度相同的字符串string2

我只被允许使用Prelude功能length

例如:将 asstring1 "Key"和我的名字"Ahmed"作为string2函数应该返回"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

我认为这可能与我的列表用完并变成一个空列表(?)有关。

一点帮助将不胜感激。

4

3 回答 3

1

我认为这段代码足以解决您的问题:

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'函数将循环第一个字符串,直到被消耗,然后将再次开始消耗它。

您还可以使用takecycle类似功能:

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]
于 2015-05-19T11:19:39.177 回答
1

就像卡斯滕说的,你应该

  • 处理列表为空的情况
  • 当你删除它时,将第一个元素推到列表的末尾。
  • 当 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"
于 2015-05-19T11:29:54.947 回答
0

注意:这个答案是用literate Haskell写的。将其另存为Filename.lhs并在 GHCi 中尝试。

我认为在这种情况下这length是一个红鲱鱼。您可以仅通过递归和模式匹配来解决这个问题,这甚至可以在很长的列表上工作。但首先要做的事情。

我们的函数应该有什么类型?我们正在使用两个字符串,我们将一遍又一遍地重复第一个字符串,这听起来像String -> String -> String. 然而,这种“一遍又一遍”的事情并不是字符串所独有的:你可以对每一种列表都这样做,所以我们选择以下类型:

> repeatFirst :: [a] -> [b] -> [a]
> repeatFirst as bs = go as bs

好的,到目前为止,没有什么特别的事情发生,对吧?我们根据 定义repeatFirstgo这仍然是缺失的。在go我们想要将 的项bs与 的对应项进行交换时as,我们已经知道了一个基本情况,即如果bs为空会发生什么:

>    where go  _     []     = []

如果bs不是空的呢?在这种情况下,我们要使用来自 的正确项目as。所以我们应该同时遍历两者:

>          go (x:xs) (_:ys) = x : go xs ys

我们目前正在处理以下情况:空的第二个参数列表和非空列表。我们仍然需要处理空的第一个参数列表:

>          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,zipWithconst如果您没有约束:

repeatFirst :: [a] -> [b] -> [a]
repeatFirst = zipWith const . cycle

但这可能是另一个问题。

于 2016-01-13T21:25:17.313 回答