我有以下测试案例:
abc :: ABC
abc = ['A'..'Z'] ++ ['a'..'z']
startState :: ABC -> String -> Maybe (String, [Char], [Char])
startState abc "Save Our Souls" == Just ("SAVE OUR SOULS", "", "")
startState abc "Save Our Souls!" == Nothing
简而言之,如果字符串包含的字符不是abc的一部分(在示例中,第三行包含!),则该函数应不输出任何内容,否则应像示例中那样打印字符串。 / p>
这是我的代码:
startState :: ABC -> String -> Maybe (String, [Char], [Char])
startState abc "" = Just ("","","")
startState abc word = Just (word,"","")
startState abc word
| word `elem` abc = Just (word,"","")
| otherwise = Nothing
我得到错误:Couldn't match type Char' with
[Char]'
答案 0 :(得分:2)
您收到错误Couldn't match type ‘Char’ with ‘[Char]’
,因为您试图将elem
应用于类型为word
的{{1}}和类型为[Char]
的{{1}}也输入abc
,而[Char]
的类型签名是:
elem
因此,在您的情况下,应将其应用于elem :: (Foldable t, Eq a) => a -> t a -> Bool
和Char
:
[Char]
如果要检查elem :: Char -> [Char] -> Bool
的所有字符是否都是word
的元素,则可以使用函数Data.List.all
执行以下操作:
abc
这会将功能startState abc word
| all (flip elem abc) word = Just (word,"","")
| otherwise = Nothing
应用于flip elem abc
中的每个字符,并且当所有字符都是word
的元素时返回True
。
您还应该删除这两行:
abc
因为您不需要第一个,而第二个与第三个模式相同,所以它将使第三个模式匹配变得多余。并且还需要在startState abc "" = Just ("","","")
startState abc word = Just (word,"","")
的定义中添加++ [' ']
,以使测试用例通过。
答案 1 :(得分:1)
假设ABC
是String
的同义词,那么错误就出在这里:
| word `elem` abc = Just (word,"","")
elem
的类型签名为a -> [a] -> Bool
。由于word
和abc
基本上都具有String
的类型,因此这不适合elem
的类型签名。
由于您要测试word
的每个元素,因此这是一种解决方案:
| all (`elem` abc) word = Just (word,"","")
all
来自前奏。
编辑:另外请注意,abc
是不明确的。它定义为类型为ABC
的常量,但它也是startState
的参数。删除该参数:
abc :: ABC
abc = ['A'..'Z'] ++ ['a'..'z']
startState :: String -> Maybe (String, [Char], [Char])
startState "" = Just ("","","")
startState word
| word `elem` abc = Just (word,"","")
| otherwise = Nothing
答案 2 :(得分:0)
另一种替代方法是将其全部打包到一个函数中,并使用软件包ord
中的函数Data.Char
。该函数将字符转换为等效的十进制数。通过检查ascii表,您可以清楚地看到所需字符的边界。下面的代码:
conv :: String -> String
conv (x:xs)
| ord >= 65 && ord x <= 91 = [x] ++ conv xs
| ord >= 97 && ord x <= 122 = [x] ++ conv xs
| otherwise = "" ++ conv xs