在Haskell

时间:2018-03-24 12:22:46

标签: haskell

我试图在Haskell中编写这个函数,名为scanString,它接受一个字符串并将其转换为int,如果它只由数字组成,否则应返回0。

例如,scanString“123”= 123但scanString“12a”= 0。

到目前为止,这是我的实现:

scanChar :: Char -> Int
scanChar c
  | 48 <= fromEnum c && fromEnum c <= 57 = (fromEnum c) - fromEnum '0'
  | otherwise = 0

scanString :: String -> Int
scanString str = case str of
  [] -> 0
  x:xs
    | 48 <= fromEnum x && fromEnum x <= 57 -> 
      ((scanChar x) * (10 ^ ((length str) -1 ))) + scanString xs
    | otherwise -> 0

此代码不正确,因为scanString“3a”会给出30。

有没有办法(比如在Java或Python中)可以简单地终止一个函数并返回一个值?当然,关于这个功能的实现的建议会很棒!

提前致谢!

4 个答案:

答案 0 :(得分:3)

我认为这里的主要问题是你让scanChar :: Char -> Int为零字符('0')以及其他字符返回零。因此,scanString必须包含额外的逻辑,这使得它更加复杂。

因此,我们可以通过返回scanChar来清除-1(或者我们可以让它返回Maybe Int并让它返回Nothing,无论您如何准确指定它,关键是尝试将检查逻辑封装在一个函数中,这样我们就不必再关心它了)。例如:

scanChar :: Char -> Int
scanChar c | '0' <= c && c <= '9' = fromEnum c - fromEnum '0'
           | otherwise = -1

现在我们可以在scanChar中封装所有数字解析逻辑。现在我们仍然需要实现scanString :: String -> Int。这可以通过编写一个与累加器一起使用的额外函数来完成。例如:

scanString :: String -> Int
scanString = go 0
    where go a s = ...

所以这里go充当模拟某种while循环的函数。 a参数是累加器,我们通过递归调用的参数,每次我们可以用更多数据更新它。最初我们将其设置为零。

go函数基本上有三种情况:

  • 到达字符串的末尾,我们可以返回累加器;
  • 字符串的第一个字符不是数字,我们返回0;和
  • 字符串的第一个字符是数字,我们将累加器与10相乘,添加解析后的值,并在字符串的尾部执行递归。

我们可以这样实现这三种情况:

scanString :: String -> Int
scanString = go 0
    where go a [] = a
          go a (x:xs) | 0 <= sc && sc <= 9 = go (10*a+sc) xs
                      | otherwise = 0
              where sc = scanChar x

答案 1 :(得分:1)

因此,您受限于最外层问题类型为String -> Int的问题的规范,但这并不意味着您的帮助函数scanChar无法返回{{1} }。

让我们看看这样做:

Maybe Int

现在,在另一个答案中使用该方法:

scanChar :: Char -> Maybe Int
scanChar c
  | 48 <= fromEnum c && fromEnum c <= 57 = Just $ (fromEnum c) - fromEnum '0'
  | otherwise = Nothing

答案 2 :(得分:1)

为什么不

scanString :: String -> Int
scanString x = if all (`elem` "0123456789") x
                 then read x :: Int
                 else 0

注意:它不会读取负整数。

或者:

import Data.Char (isDigit)
scanString' :: String -> Int
scanString' x = if all isDigit x
                then read x :: Int
                else 0

使用readMaybe simple solution here

答案 3 :(得分:0)

您可以将以下内容转换为一个带有一个字符串参数的函数。

这个函数只接受字符串中的数字并将它们打包成另一个字符串然后转换。

 [read [d | d <- "12a", elem d "1234567890"] :: Int] !! 0

收益率12

相关问题