【问题标题】:Haskell error - Couldn't match expected type ‘Char’ with actual type ‘[Char]’Haskell 错误 - 无法将预期类型“Char”与实际类型“[Char]”匹配
【发布时间】:2016-12-07 02:13:54
【问题描述】:

我正在尝试编写一个 Haskell 函数,该函数将获取一个人的全名并仅返回姓氏;例如,getName "Hans Christian Anderson" 应该返回 "Anderson"。函数如下:

getname :: String -> String
getname fullName = do
  let nameList = splitOn " " fullName    -- split the full name into individual names
  let reversedName = reverse nameList    -- reverse the full name
  let lastName = reversedName !! 0       -- get the first name from the reversed list
  return lastName

但是每当我尝试编译它时,我都会收到以下错误:

Couldn't match expected type ‘Char’ with actual type ‘[Char]’
In the first argument of ‘return’, namely ‘lastName’
In a stmt of a 'do' block: return lastName

我不确定我是否完全理解此错误。据我了解 Haskell(我对它很陌生)结构 [Char] 将与 String 相同,这就是我正在寻找的。我只是不明白为什么它期待这个Char 类型,它似乎作为字符串出现在return 语句中。我已经检查了每一行,它们对我来说似乎是正确的。

非常感谢任何关于为什么会发生这种行为以及如何解决它的建议。

【问题讨论】:

  • 这是一个很棒的编程练习。但是you might enjoy this cautionary tale about names.
  • @DanielWagner 我以前见过类似的情况,事实上,我确实考虑过我需要对所处理的名称保持谨慎,以免得到错误的结果。但是,出于本练习的目的,我可以接受有点沉重并接受很多这些假设。

标签: string haskell char


【解决方案1】:

这里不要使用do 表示法。因为您的函数的返回值是[Char],所以return 的参数应该是Char 值(因为return :: a -> [a])。

您在这里没有做任何需要do 表示法的事情;只需使用常规函数调用。

getname fullName = (reverse (splitOn " " fullName)) !! 0

【讨论】:

  • 我不确定我是否完全理解 return 为什么会这样,但我认为这是因为我没有在基于我的编码背景的功能上下文中考虑它。我没有意识到使用do ... return ... 会产生与使用常规函数调用不同的结果,但我会更多地查看文档。感谢您的回复!
  • 这就是return的目的;它的一般类型是return :: Monad m => a -> m a,但是这里的m固定为[],因为声明的返回值是getnamereturn 函数与大多数编程语言中的同名语句完全不同
  • 是的,看起来,我认为这就是让我失望的原因。我希望它的行为方式与我一直以来的行为方式相同。
【解决方案2】:

您的代码意外地在 list monad 中运行,就好像它是用来描述非确定性计算一样。你不需要那个单子,也不需要任何其他单子。因此,请避免为此使用do。如果你愿意,你仍然可以使用let .. in ..

getname :: String -> String
getname fullName =
  let nameList = splitOn " " fullName    -- split the full name into individual names
      reversedName = reverse nameList    -- reverse the full name
      lastName = reversedName !! 0       -- get the first name from the reversed list
  in lastName

或者,使用last:

getname :: String -> String
getname fullName = last (splitOn " " fullName)

注意last 是不完整的:只要输入字符串中没有名称,它就会使您的程序崩溃。更安全的方法可能是:

getname :: String -> Maybe String
getname fullName = case splitOn " " fullName of
   [] -> Nothing
   xs -> Just (last xs)

甚至:

getname :: String -> Maybe String
getname fullName = safeLast (splitOn " " fullName)

-- This should be already there in the library, IMO
safeLast :: [a] -> Maybe a
safeLast []     = Nothing
safeLast [x]    = Just x
safeLast (_:xs) = safeLast xs

【讨论】:

  • 感谢您的回复 - 关于 safeLast,也许您实际上应该向 Haskell 社区推荐它。或者失败了,我认为他们让几乎所有东西都被黑客入侵!
猜你喜欢
  • 1970-01-01
  • 2015-06-08
  • 2014-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多