haskell - 无法将类型“(Char, Int)”与“[Char]”匹配错误

haskell - Couldn't match type ‘(Char, Int)’ with ‘[Char]’ error

我正在编写一个函数来扩展字符串

示例:

foo "a4b4"

应该回馈:

"aaaabbbb"

这是我的代码:

foo :: String -> String
foo (x:xs) = let curent = fooHelp(x, read $ charToString( xs !! 0  ) :: Int)
             in x : (curent) ++ foo (tail xs)

fooHelp:

fooHelp :: String -> Int -> String
fooHelp x n 
             | n >= 3 = x ++ fooHelp x (n - 1) 
             | n == 2 = x
             | n == 1 = ""

和 charToString:

charToString :: Char -> String
charToString c = [c]

它需要 x 并将其附加到当前。在当前的 fooHelp 中将返回扩展的 String

示例:foo "a4b4" 然后 x = "a"xs = "4b4"xs !! 0 = '4' read $ charToString( xs !! 0 ) :: Int) 会将 char '4' 转换为 int 4 并将其与 x("a") -> fooHelp(x, 4) 一起传递给 fooHelp 并返回 "aaa" .然后 x : current 应该返回 "aaaa" 因为 x = "a" 和当前 "aaa" 然后用 ++ foo tail xs 递归调用 xs ="b4" 并且它应该重复这个过程。

我收到错误:

test.hs:173:34: error:
    • Couldn't match type ‘(Char, Int)’ with ‘[Char]’
      Expected type: String
        Actual type: (Char, Int)
    • In the first argument of ‘fooHelp’, namely
        ‘(x, read $ charToString (xs !! 0) :: Int)’
      In the expression:
        fooHelp (x, read $ charToString (xs !! 0) :: Int)
      In an equation for ‘curent’:
          curent = fooHelp (x, read $ charToString (xs !! 0) :: Int)
    |
173 | foo (x:xs) = let curent = fooHelp(x, read $ charToString( xs !! 0  ) :: Int)
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我哪里弄错了?我测试了函数 fooHelp,它可以很好地处理 foo 中的参数。

正在测试 fooHelp:

xs = "4b4"

test =  read $ charToString( xs !!0 ) :: Int

*Main> test
4

表达式 fooHelp(x, read $ charToString( xs !! 0 ) :: Int) 试图将单个参数 — (Char, Int) 对 — 传递给 fooHelp,这是错误的。据推测,您想改写:

fooHelp (charToString x) (read $ charToString( xs !! 0  ) :: Int)

一个典型的错误是调用像 f (x1, x2) 这样的函数。在 Haskell 函数中有 一个 参数,通常这是 而不是 一个元组。

您的 fooHelper 函数的类型为:

fooHelp :: String -> (Int -> String)

所以它是一个接受 String 的函数,而 returns 是一个将 Ints 映射到 Strings 的函数。因此,您应该像这样调用该函数:

(fooHelp x) (read $ charToString( xs !! 0  ) :: Int)

或更简洁:

(fooHelp x) (read $ charToString( xs !! 0  ) :: Int)

但现在类型仍然不匹配:xChar,不是 String,您可以将其包装在列表中,如:

fooHelp [x] (read $ charToString( xs !! 0  ) :: Int)

喜欢:

foo :: String -> String
foo (x:xs) = let curent = fooHelp [x] (read $ charToString( xs !! 0  ) :: Int)
             in x : (curent) ++ foo (tail xs)

但是这个函数仍然有一个问题:我们遍历字符串,所以最终我们会得到一个空字符串,而 foo 没有这种情况。在这种情况下,我们需要 return 空字符串,例如:

foo :: String -> String
foo (x:xs) = let curent = fooHelp [x] (read $ charToString( xs !! 0  ) :: Int)
             in x : (curent) ++ foo (tail xs)
foo [] = ""

但还是不够优雅。我们在这里执行了很多不必要的操作,比如将字符包装成字符串等

我们可以使用replicate :: Int -> a -> [a]函数来重复一个字符给定的次数。例如:

Prelude> replicate 3 'a'
"aaa" 

另外digitToInt :: Char -> Int函数可以将一个数字字符解析为对应的Int:

Prelude Data.Char> digitToInt '3'
3 

所以我们在这里可以使用这两个来每次获取字符串的前两个字符,并使用 replicate (digitToInt k) x 生成一个字符串,其中 x si 重复请求的时间量,并且对字符串的其余部分执行递归,例如:

import Data.Char(digitToInt)

foo :: String -> String
foo (x:k:xs) = replicate (digitToInt k) x ++ foo xs
foo _ = ""