我正在做家庭作业,我们有一组混合元素Char和Int。
我创建了这个自定义类型:
data Element = CharToElement Char | IntToElement Int
将Char
和Int
转换为Element
,以便我可以处理它们。
我遇到的问题是当我想转换回来时该怎么做?
现在我做(头部数组)并返回Element
如何将Element
转换为Int
或Char
。
这是针对后缀评估程序的。
帮助表示赞赏。感谢。
编辑:
所以我努力了,这就是我所拥有的:
data Element = ElementConstructor (Char, Int, Bool) | IntToElement Int | CharToElement Char | NIL
extractInt (_,i,_) = i
extractChar (c,_,_) = c
extractType (_,_,b) = b
stack_push :: [Element] -> Element -> [Element]
stack_push stack element = (element:stack)
stack_pop :: [Element] -> [Element]
stack_pop stack = (tail stack)
stack_top :: [Element] -> Element
stack_top stack = (head stack)
postfix_eval eqn = (postfix_eval_rec (postfix_eval_const eqn []) [])
postfix_eval_const eqn_raw eqn_conv =
if null eqn_raw
then NIL
else
if (isNumber (head eqn_raw))
then ElementConstructor(NIL, (head eqn_raw), True):eqn_conv
else if (isAlpha (head eqn_raw))
then ElementConstructor((head eqn_raw), NIL, False):eqn_conv
postfix_eval_const (tail eqn_raw) eqn_conv
operate :: Element -> Element -> Element -> Element
operate operator_char a b =
if operator_char == '+'
then IntToElement ( (extractInt a) + (extractInt b) )
else if operator_char == '-'
then IntToElement ( (extractInt b) - (extractInt a) )
else if operator_char == '*'
then IntToElement ( (extractInt a) * (extractInt b) )
else if operator_char == '/'
then IntToElement ( (extractInt b) `div` (extractInt a) )
else
IntToElement(0)
postfix_eval_rec :: [Element] -> [Element] -> Int
postfix_eval_rec eqn stack =
if null eqn
then (extractInt (stack_top stack))
else if ( (extractType (head eqn)) )
then (postfix_eval_rec (tail eqn) (stack_push stack (head eqn) ) )
else
(postfix_eval_rec (tail stack) (stack_push (stack_pop (stack_pop stack)) (operate (head eqn) (stack_top stack) (stack_top (stack_pop stack)))))
这个想法是你输入的内容如下: postfix_eval [1,2,3,' +',4,' +',' *'] 你会得到一个Int形式的答案,在这种情况下你得到9
答案 0 :(得分:4)
有很多方法可以解决这个问题。我只会提供一些一般性的建议。
首先,努力只使用总函数 - 从不出错的函数。特别是,head
,tail
在大多数惯用的Haskell代码中都是不必要的,应该被视为代码气味。
此外,避免可以用模式匹配替换的if
/警卫。你真的应该习惯这一点,周围有good tutorials。
例如,这是您operate
函数的第一次修改:
operate :: Element -> Element -> Element -> Element
operate (CharToElement '+') a b =
IntToElement (extractInt a + extractInt b)
operate (CharToElement '-') a b =
IntToElement (extractInt a - extractInt b)
operate (CharToElement '*') a b =
IntToElement (extractInt a * extractInt b)
operate (CharToElement '/') a b =
IntToElement (extractInt a `div` extractInt b)
operate _ _ _ =
IntToElement 0
这远非完美。首先,为什么在错误时返回0
?调用者无法将其与实际的null结果区分开来。其次,函数extractInt
必然是部分的(或者再次返回虚假结果):如果a
是char而不是什么?
最终,在类型级别已经找到了最大的谎言:
operate :: Element -> Element -> Element -> Element
这种类型确实存在:对于所有输入,我们并不总是得到Element
。我们想要改造错误。这更诚实:
operate :: Element -> Element -> Element -> Maybe Element
并且可以通过模式匹配再次实现:
operate :: Element -> Element -> Element -> Maybe Element
operate (CharToElement '+') (IntToElement a) (IntToElement b) =
Just $ IntToElement $ a + b
operate (CharToElement '-') (IntToElement a) (IntToElement b) =
Just $ IntToElement $ a - b
operate (CharToElement '*') (IntToElement a) (IntToElement b) =
Just $ IntToElement $ a * b
operate (CharToElement '/') (IntToElement a) (IntToElement b) =
Just $ IntToElement $ a `div` b
operate _ _ _ =
Nothing
瞧,不需要危险的extract
功能。当输入不是整数时,我们只返回Nothing
,因为第一次匹配失败。
这可能感觉不太方便,因为现在我们需要处理其余代码中的Maybe Element
,这些代码不再需要使用简单的Element
。但这是重点!代码的其余部分需要来处理可能的错误,因此必须在那里执行错误处理。 Maybe Element
类型迫使我们这样做。