String Haskell语法,傻瓜解析错误
今天我读了很多关于Haskell的书,但这种形成方式让我发疯。我想尽快理解我的基本错误,这样我就可以开始正常编码了。此处的函数应返回以下一个“数学符号”示例字符串开头的字符串String Haskell语法,傻瓜解析错误,string,parsing,haskell,syntax,String,Parsing,Haskell,Syntax,今天我读了很多关于Haskell的书,但这种形成方式让我发疯。我想尽快理解我的基本错误,这样我就可以开始正常编码了。此处的函数应返回以下一个“数学符号”示例字符串开头的字符串(2sdwds+asd)+3应返回+asd)+3。 这是密码 getToNextSign :: String -> String getToNextSign str = do let mathSigns = ['+' , '-' , '*' , '/' , '^' , ')'] let a = head str i
(2sdwds+asd)+3
应返回+asd)+3
。
这是密码
getToNextSign :: String -> String
getToNextSign str = do
let mathSigns = ['+' , '-' , '*' , '/' , '^' , ')']
let a = head str
if a `elem` mathSigns
then str
else if tail str /= []
then getToNextSign $ tail str
else []
main = do
putStrLn $ getToNextSign "(2sdwds+asd)+3"
它给我“输入时解析错误=”。我也不确定如何准确地在main中调用它,我是否真的需要putStrLn函数。我不认为我需要它,但我尝试了2874种不同的方法来编写它,现在我放弃了,需要帮助。Haskell对空格敏感,必须将函数体缩进到顶级之外。直接修复原始代码的方法是:
getToNextSign :: String -> String
getToNextSign str = do
let mathSigns = ['+' , '-' , '*' , '/' , '^' , ')']
let a = head str
if a `elem` mathSigns
then str
else if tail str /= []
then getToNextSign $ tail str
else []
main = do
putStrLn $ getToNextSign "(2sdwds+asd)+3"
正如评论中指出的,这里不需要do符号,因为您没有使用monad。let语句可以写成where语句
getToNextSign :: String -> String
getToNextSign str =
if a `elem` mathSigns
then str
else if tail str /= []
then getToNextSign $ tail str
else []
where
a = head str
mathSigns = ['+' , '-' , '*' , '/' , '^' , ')']
除了Stephen Diehl提供的格式改进之外,您还可以进行其他改进。正如Carl指出的,您可以用防护装置替换if-else,如下所示:
getToNextSign :: String -> String
getToNextSign str
| a `elem` mathSigns = str
| tail str /= [] = getToNextSign $ tail str
| otherwise = []
where
a = head str
mathSigns = ['+' , '-' , '*' , '/' , '^' , ')']
当您使用时,还可以使用模式匹配替换头部/尾部,如中所示
getToNextSign :: String -> String
getToNextSign (c:cs)
| c `elem` mathSigns = c:cs
| not (null cs) = getToNextSign cs
| otherwise = []
where
mathSigns = ['+' , '-' , '*' , '/' , '^' , ')']
如果你要做模式匹配,你也可以一直做下去
getToNextSign :: String -> String
getToNextSign str = case str of
c:_ | c `elem` mathSigns -> str
c:[] -> []
_:cs -> getToNextSign cs
where mathSigns = ['+' , '-' , '*' , '/' , '^' , ')']
当你这样做的时候,你会发现你还没有真正处理过当
getToNextSign
获取一个空列表作为参数时的情况,这可能是你想要做的事情。这里有一个简单的替代方法,使用Prelude list函数,dropWhile
和elem
,它的类型是sig(a->Bool)->[a]->[a]
。它使用一个函数,只要函数提供的条件为true,该函数就会从列表中删除元素
因此,您的函数可以重写如下
let getNextSign x = dropWhile ( not . `elem` "+-*/^)" ) x
尽可能避免显式递归,并充分利用高阶函数。《序曲》中有大量的列表操作函数,这些函数随时都会派上用场。您在这里发布的代码是否与源文件中缩进的代码完全相同?似乎是缩进中的语法错误。2件与您的错误无关的小事:如果您不使用Monad,则不应使用do符号,我更希望使用stdlib中的函数来完成此任务(break/span/etc)。是的,代码是1对1。我知道可能是身份证上的,但我找不到。还有@missingno我想我明白你的意思了,但正如我说的,我尝试了许多不同的方法,但不明白错误在哪里,我想我在第一次默示时没有使用“do”。真的谢谢你。我想我必须检查每个空间。但是一个完整的空白行是一个问题,因为这似乎是唯一的区别。@user3129475不,这甚至不是唯一的区别。重要的区别在于函数体必须缩进。您没有缩进if,但必须缩进。@StephenDiehl我强烈建议使用第三个版本,使用防护而不是嵌套的if。这正是他们使用这种语言的原因。@Carl你能和警卫一起看一下吗?我知道怎么做,但实际上不行。@user3129475评论太长了,所以我把它记下来了。非常感谢。当它得到一个空列表时,我没有处理这个案例,因为我在调用它之前检查列表是否为空。我将很快发布另一个问题,因为我的下一个功能是使用防护,我希望我能正确地使用它们,但我想我也需要帮助。这很好。我们可以使用
getToNextSign[]=[]
进一步重构,然后getToNextSign str@(c:cs)
| c`elem`mathSigns=str
;否则->getToNextSign cs
@enoreptomment我考虑过这个问题,但决定不包括它,因为它会引入另一个(可能的)元素外来概念–模式中的@
别名。