2016-12-06 73 views
0

我正在尝试编写一个Haskell函数,它将采用一个人的全名并仅返回姓氏;例如,getName "Hans Christian Anderson"应返回"Anderson"。功能如下:Haskell错误 - 无法与实际类型'Char'匹配的预期类型''Char''

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类型,它似乎是作为一个字符串出现在返回语句。我已经完成了每一行,他们似乎对我来说是正确的。

任何意见,为什么这种行为正在发生,以及如何解决它非常感谢。

+1

这是一个伟大的编程工作。但[你可能会喜欢这个关于名称的警示性故事](https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/)。 –

+0

@DanielWagner我以前见过类似的东西,事实上我确实考虑过我需要对我处理的名称持谨慎态度,以免得到错误的结果。然而,为了这个练习的目的,我可以接受一点,那就是有很多这样的假设。 –

回答

5

请勿在此处使用do表示法。由于函数的返回值为[Char],因此return的参数预计为Char值(因为return :: a -> [a])。

你在这里没做任何事,需要do表示法;只是使用常规函数调用。

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

我不确定我完全理解为什么返回的行为是这样的,但我认为这是因为我没有根据我的编码背景在功能上下文中考虑它。我没有意识到使用'do ... return ...'会产生使用常规函数调用的任何不同结果,但我会更多地查看文档。感谢您的答复! –

+2

这就是'return'的目的;它的通用类型是'return :: Monad m => a - > m a',但由于'getname'的声明返回值,因此'm'被固定为'[]'。 'return'函数与大多数编程语言中的同名语句没什么两样 – chepner

+0

是的,所以看起来,我认为这就是把我抛弃的原因。我预料它会像我一直认为它的行为一样。 –

2

您的代码意外地在列表monad中工作,好像它是为了描述非确定性计算。你不需要那个monad,也不需要其他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 
+0

感谢您的回应 - 关于safeLast,也许您应该将其推荐给Haskell社区。否则,我认为他们只是在黑客上做所有事情! –

相关问题