在 Haskell 中生成逻辑表达式的真值表
第一部分是具有以下类型签名的求值函数:
evaluate :: Logic Expr -> [(Variable, Bool)] -> Bool
它采用逻辑表达式和赋值对列表作为输入,并根据提供的布尔赋值返回表达式的值。 赋值列表是一个不同的对列表,其中每对包含一个变量及其布尔赋值。 也就是说,如果将表达式 A ∧ B 和赋值 A = 1 且 B = 0 传递给函数,则函数必须返回 0(这来自数字逻辑设计,0 对应于 false,1 对应于 true)。
这就是我到目前为止所做的:
type Variable = Char
data LogicExpr = V Variable
| Negation LogicExpr
| Conjunction LogicExpr LogicExpr
| Disjunction LogicExpr LogicExpr
| Implication LogicExpr LogicExpr
evaluate :: LogicExpr -> [(Variable,Bool)] -> Bool
evaluate (V a) ((x1,x2):xs) | a==x1 = x2
| otherwise = (evaluate(V a)xs)
evaluate (Negation a) l | (evaluate a l)==True = False
| otherwise = True
evaluate (Conjunction a b) l = (evaluate a l)&&(evaluate b l)
evaluate (Disjunction a b) l = (evaluate a l)||(evaluate b l)
evaluate (Implication a b) l
| (((evaluate b l)==False)&&((evaluate a l)==True)) = False
| otherwise = True
下一部分是定义generateTruthTable
,它是一个函数,它将逻辑表达式作为输入并以列表的形式返回表达式的真值表作业对列表。 也就是说,如果将表达式 E = A ∧ B 传递给函数,则函数必须返回 A = 0, B = 0, E = 0 | A = 0,B = 1,E = 0 | A = 1,B = 0,E = 0 | A = 1,B = 1,E = 1。
我不太熟悉语法,所以我不知道如何返回列表。
The first part is an evaluation function that has the following type signature:
evaluate :: Logic Expr -> [(Variable, Bool)] -> Bool
This takes a logic expression and a list of assignment pairs as input and returns the value of the expression according to the Boolean assignment provided. The assignment list is a distinct list of pairs where each pair contains a variable and its Boolean assignment. That is, if you pass to the function the expression A ∧ B and the assignment A = 1 and B = 0, your function must return 0 (this comes from Digital Logic Design, 0 corresponds to false, and 1 corresponds to true).
This is what I managed to do so far:
type Variable = Char
data LogicExpr = V Variable
| Negation LogicExpr
| Conjunction LogicExpr LogicExpr
| Disjunction LogicExpr LogicExpr
| Implication LogicExpr LogicExpr
evaluate :: LogicExpr -> [(Variable,Bool)] -> Bool
evaluate (V a) ((x1,x2):xs) | a==x1 = x2
| otherwise = (evaluate(V a)xs)
evaluate (Negation a) l | (evaluate a l)==True = False
| otherwise = True
evaluate (Conjunction a b) l = (evaluate a l)&&(evaluate b l)
evaluate (Disjunction a b) l = (evaluate a l)||(evaluate b l)
evaluate (Implication a b) l
| (((evaluate b l)==False)&&((evaluate a l)==True)) = False
| otherwise = True
The next part is to define generateTruthTable
, which is a function that takes a logic expression as input and returns the truth table of the expression in the form of a list of lists of assignment pairs. That is, if you pass to the function the expression E = A ∧ B, your function must return A = 0, B = 0, E = 0 | A = 0, B = 1, E = 0 | A = 1, B = 0, E = 0 | A = 1, B = 1, E = 1.
I'm not exactly familiar with the syntax so I don't know how to return the list.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
标准库函数,代码复用。 另外,你的括号用法和间距真的很糟糕。
现在,您想要一个
generateTruthTable
吗? 这很简单,只需获取布尔变量的所有可能状态,并将计算的表达式附加到每个变量的末尾即可。如果你有一个函数来生成所有这些可能的状态就好了。
根据我的功能性直觉,这感觉应该是一种变形。 毕竟,它确实需要查看列表中的所有内容,但返回不同结构的内容,并且它可能可以以简单的方式分解,因为这是一个入门级 CS 类。 (我不在乎课程编号是什么,这是介绍性的东西。)
现在,foldr :: (a -> b -> b) -> b-> [一]-> b,所以前两个参数必须是
step::a -> b-> b
和initial :: b
。 现在,allPossible :: [Variable] -> [[(Variable, Bool)]] =foldr 步骤初始 :: [a] -> b。 嗯,这肯定意味着a = Variable
和b = [[(Variable, Bool)]]
。 这对于step
和initial
意味着什么?有趣的。 无论如何,需要有一种方法从变量状态列表中
step
并向其中添加单个变量,以及一些根本没有变量的initial
列表。如果您已经成功地“点击”了函数式编程范例,那么这应该已经足够了。 如果没有,那么无论您在这里收到什么指示,在作业到期时的几个小时内您都会被搞砸。 祝你好运,如果你在作业到期后仍然遇到困难,你应该询问你的教授,或者在这里问一个不紧急的问题。
如果您对该语言有基本的可用性问题(“语法是什么”、“运行时语义是什么”、“xxx 是否有预先存在的功能”等) :
我希望你们的班级提供了类似的资源,但如果没有,以上所有内容都可以通过 Google 搜索轻松找到。
如果有适当的参考,任何值得自己salt的程序员都应该能够掌握语法在几个小时内掌握任何新语言,并在几天内对运行时有一个有效的理解。 当然,掌握一种新范式可能需要很长时间,而且让学生遵守相同的标准有些不公平,但这就是课程的目的。
关于 Stack Overflow 上更高级别问题的问题可能会得到更少的答案,但他们也会得到更少的脾气:)家庭作业问题被归类为“为我做我的工作!” 在大多数人眼里。
剧透
请不要作弊。 然而,只是为了让您体验一下 Haskell 可以完成多么出色的事情......
B'+ :) . showsPrec 9 v showsPrec _ (Invert e) = ('!':) . showsPrec 9 e showsPrec n e@(a:=>b) | n > 5 = paren $ showsPrec 0 e | otherwise = showsPrec 7 a . ('=':) . ('>':) . showsPrec 5 b showsPrec n e@(a:*b) | n > 7 = paren $ showsPrec 0 e | otherwise = showsPrec 7 a . ('*':) . showsPrec 7 b showsPrec n e | n > 6 = paren $ showsPrec 0 e showsPrec _ (a:+b) = showsPrec 6 a . ('+':) . showsPrec 6 b showsPrec _ (a:-b) = showsPrec 6 a . ('-':) . showsPrec 6 b vars :: (Eq a) => Expr a b -> [a] vars (a:+b) = vars a ++ vars b vars (a:-b) = vars a ++ vars b vars (a:*b) = vars a ++ vars b vars (a:=>b) = vars a ++ vars b vars (Invert e) = vars e; vars (Var v) = [v]; vars _ = [] eval :: (Eq a, Show a, Ring b, Monad m) => [(a, b)] -> Expr a b -> m b eval m (a:+b) = return (+:) `ap` eval m a `ap` eval m b eval m (a:-b) = return (-:) `ap` eval m a `ap` eval m b eval m (a:*b) = return (*:) `ap` eval m a `ap` eval m b eval m (a:=>b) = return (=:>) `ap` eval m a `ap` eval m b eval m (Invert e) = return invert `ap` eval m e eval m (Var v) | Just c <- lookup v m = return c | otherwise = fail $ "Unbound variable: " ++ show v eval _ (Const c) = return c namedProduct :: [(a, [b])] -> [[(a, b)]] namedProduct = foldr (\(v, cs) l -> concatMap (\c -> map ((v, c):) l) cs) [[]] evalAll :: (Eq a, Show a, Ring b) => [b] -> a -> Expr a b -> [[(a, b)]] evalAll range name e = [ vs ++ [(name, either error id $ eval vs e)] | vs <- namedProduct $ zip (vars e) (repeat range) ]C')* :) . showsPrec 9 v showsPrec _ (Invert e) = ('!':) . showsPrec 9 e showsPrec n e@(a:=>b) | n > 5 = paren $ showsPrec 0 e | otherwise = showsPrec 7 a . ('=':) . ('>':) . showsPrec 5 b showsPrec n e@(a:*b) | n > 7 = paren $ showsPrec 0 e | otherwise = showsPrec 7 a . ('*':) . showsPrec 7 b showsPrec n e | n > 6 = paren $ showsPrec 0 e showsPrec _ (a:+b) = showsPrec 6 a . ('+':) . showsPrec 6 b showsPrec _ (a:-b) = showsPrec 6 a . ('-':) . showsPrec 6 b vars :: (Eq a) => Expr a b -> [a] vars (a:+b) = vars a ++ vars b vars (a:-b) = vars a ++ vars b vars (a:*b) = vars a ++ vars b vars (a:=>b) = vars a ++ vars b vars (Invert e) = vars e; vars (Var v) = [v]; vars _ = [] eval :: (Eq a, Show a, Ring b, Monad m) => [(a, b)] -> Expr a b -> m b eval m (a:+b) = return (+:) `ap` eval m a `ap` eval m b eval m (a:-b) = return (-:) `ap` eval m a `ap` eval m b eval m (a:*b) = return (*:) `ap` eval m a `ap` eval m b eval m (a:=>b) = return (=:>) `ap` eval m a `ap` eval m b eval m (Invert e) = return invert `ap` eval m e eval m (Var v) | Just c <- lookup v m = return c | otherwise = fail $ "Unbound variable: " ++ show v eval _ (Const c) = return c namedProduct :: [(a, [b])] -> [[(a, b)]] namedProduct = foldr (\(v, cs) l -> concatMap (\c -> map ((v, c):) l) cs) [[]] evalAll :: (Eq a, Show a, Ring b) => [b] -> a -> Expr a b -> [[(a, b)]] evalAll range name e = [ vs ++ [(name, either error id $ eval vs e)] | vs <- namedProduct $ zip (vars e) (repeat range) ]D' *Expr> mapM_ print $ evalAll [True, False] 'E' expr [('A',True),('B',True),('C',True),('D',True),('E',True)] [('A',True),('B',True),('C',True),('D',False),('E',False)] [('A',True),('B',True),('C',False),('D',True),('E',True)] [('A',True),('B',True),('C',False),('D',False),('E',False)] [('A',True),('B',False),('C',True),('D',True),('E',True)] [('A',True),('B',False),('C',True),('D',False),('E',False)] [('A',True),('B',False),('C',False),('D',True),('E',False)] [('A',True),('B',False),('C',False),('D',False),('E',False)] [('A',False),('B',True),('C',True),('D',True),('E',True)] [('A',False),('B',True),('C',True),('D',False),('E',True)] [('A',False),('B',True),('C',False),('D',True),('E',True)] [('A',False),('B',True),('C',False),('D',False),('E',True)] [('A',False),('B',False),('C',True),('D',True),('E',True)] [('A',False),('B',False),('C',True),('D',False),('E',True)] [('A',False),('B',False),('C',False),('D',True),('E',True)] [('A',False),('B',False),('C',False),('D',False),('E',True)] :) . showsPrec 9 v showsPrec _ (Invert e) = ('!':) . showsPrec 9 e showsPrec n e@(a:=>b) | n > 5 = paren $ showsPrec 0 e | otherwise = showsPrec 7 a . ('=':) . ('>':) . showsPrec 5 b showsPrec n e@(a:*b) | n > 7 = paren $ showsPrec 0 e | otherwise = showsPrec 7 a . ('*':) . showsPrec 7 b showsPrec n e | n > 6 = paren $ showsPrec 0 e showsPrec _ (a:+b) = showsPrec 6 a . ('+':) . showsPrec 6 b showsPrec _ (a:-b) = showsPrec 6 a . ('-':) . showsPrec 6 b vars :: (Eq a) => Expr a b -> [a] vars (a:+b) = vars a ++ vars b vars (a:-b) = vars a ++ vars b vars (a:*b) = vars a ++ vars b vars (a:=>b) = vars a ++ vars b vars (Invert e) = vars e; vars (Var v) = [v]; vars _ = [] eval :: (Eq a, Show a, Ring b, Monad m) => [(a, b)] -> Expr a b -> m b eval m (a:+b) = return (+:) `ap` eval m a `ap` eval m b eval m (a:-b) = return (-:) `ap` eval m a `ap` eval m b eval m (a:*b) = return (*:) `ap` eval m a `ap` eval m b eval m (a:=>b) = return (=:>) `ap` eval m a `ap` eval m b eval m (Invert e) = return invert `ap` eval m e eval m (Var v) | Just c <- lookup v m = return c | otherwise = fail $ "Unbound variable: " ++ show v eval _ (Const c) = return c namedProduct :: [(a, [b])] -> [[(a, b)]] namedProduct = foldr (\(v, cs) l -> concatMap (\c -> map ((v, c):) l) cs) [[]] evalAll :: (Eq a, Show a, Ring b) => [b] -> a -> Expr a b -> [[(a, b)]] evalAll range name e = [ vs ++ [(name, either error id $ eval vs e)] | vs <- namedProduct $ zip (vars e) (repeat range) ]Standard library functions, reuse of code. Also, your parentheses usage and spacing are really whacked.
Now, you want a
generateTruthTable
? That's easy, just take all the possible states of the boolean variables, and tack the evaluated expression on to the end of each.If only you had a function to generate all those possible states.
Following my functional gut instinct, this feels like it should be a catamorphism. After all, it does need to look at everything in the list, but return something of a different structure, and it can probably be broken down in a simple way because this is an intro-level CS class. (I don't care what the course number is, this is introductory stuff.)
Now,
foldr :: (a -> b -> b) -> b -> [a] -> b
, so the first two parameters must bestep :: a -> b -> b
andinitial :: b
. Now,allPossible :: [Variable] -> [[(Variable, Bool)]] = foldr step initial :: [a] -> b
. Hmm, this must mean thata = Variable
andb = [[(Variable, Bool)]]
. What does this mean forstep
andinitial
?Interesting. Somehow, there needs to be a way to
step
from a list of variable states and add a single variable to it, and someinitial
list with no variables at all.If your mind has managed to "click" into the functional programming paradigm already, this should be more than sufficient. If not, you're pretty much screwed in a couple of hours when the assignment is due, regardless of what instruction you've received here. Good luck, and if you're still stuck after the assignment is due, you should ask your professor, or ask a non-urgent question here.
If you're having basic usability issues with the language ("what is the syntax", "what are the run-time semantics", "is there pre-existing functionality for xxx", etc.):
I hope your class has provided similar resources, but if not, all of the above are easily discoverable from a Google search.
Given proper references, any programmer worth his or her own salt should be able to pick up the syntax of any new language within a few hours, and have a working understanding of the runtime within days. Of course, mastering a new paradigm may take ages, and it's somewhat unfair to hold students to the same standards, but that's what the class is for.
Questions about higher-level problems on Stack Overflow may invite less answers, but they'll also be provided with far less petulance :) Homework questions are categorized as "do my work for me!" in most peoples' eyes.
Spoiler
Please don't cheat. However, just to give you a taste of how awesome stuff can be done in Haskell...
B'+ :) . showsPrec 9 v showsPrec _ (Invert e) = ('!':) . showsPrec 9 e showsPrec n e@(a:=>b) | n > 5 = paren $ showsPrec 0 e | otherwise = showsPrec 7 a . ('=':) . ('>':) . showsPrec 5 b showsPrec n e@(a:*b) | n > 7 = paren $ showsPrec 0 e | otherwise = showsPrec 7 a . ('*':) . showsPrec 7 b showsPrec n e | n > 6 = paren $ showsPrec 0 e showsPrec _ (a:+b) = showsPrec 6 a . ('+':) . showsPrec 6 b showsPrec _ (a:-b) = showsPrec 6 a . ('-':) . showsPrec 6 b vars :: (Eq a) => Expr a b -> [a] vars (a:+b) = vars a ++ vars b vars (a:-b) = vars a ++ vars b vars (a:*b) = vars a ++ vars b vars (a:=>b) = vars a ++ vars b vars (Invert e) = vars e; vars (Var v) = [v]; vars _ = [] eval :: (Eq a, Show a, Ring b, Monad m) => [(a, b)] -> Expr a b -> m b eval m (a:+b) = return (+:) `ap` eval m a `ap` eval m b eval m (a:-b) = return (-:) `ap` eval m a `ap` eval m b eval m (a:*b) = return (*:) `ap` eval m a `ap` eval m b eval m (a:=>b) = return (=:>) `ap` eval m a `ap` eval m b eval m (Invert e) = return invert `ap` eval m e eval m (Var v) | Just c <- lookup v m = return c | otherwise = fail $ "Unbound variable: " ++ show v eval _ (Const c) = return c namedProduct :: [(a, [b])] -> [[(a, b)]] namedProduct = foldr (\(v, cs) l -> concatMap (\c -> map ((v, c):) l) cs) [[]] evalAll :: (Eq a, Show a, Ring b) => [b] -> a -> Expr a b -> [[(a, b)]] evalAll range name e = [ vs ++ [(name, either error id $ eval vs e)] | vs <- namedProduct $ zip (vars e) (repeat range) ]C')* :) . showsPrec 9 v showsPrec _ (Invert e) = ('!':) . showsPrec 9 e showsPrec n e@(a:=>b) | n > 5 = paren $ showsPrec 0 e | otherwise = showsPrec 7 a . ('=':) . ('>':) . showsPrec 5 b showsPrec n e@(a:*b) | n > 7 = paren $ showsPrec 0 e | otherwise = showsPrec 7 a . ('*':) . showsPrec 7 b showsPrec n e | n > 6 = paren $ showsPrec 0 e showsPrec _ (a:+b) = showsPrec 6 a . ('+':) . showsPrec 6 b showsPrec _ (a:-b) = showsPrec 6 a . ('-':) . showsPrec 6 b vars :: (Eq a) => Expr a b -> [a] vars (a:+b) = vars a ++ vars b vars (a:-b) = vars a ++ vars b vars (a:*b) = vars a ++ vars b vars (a:=>b) = vars a ++ vars b vars (Invert e) = vars e; vars (Var v) = [v]; vars _ = [] eval :: (Eq a, Show a, Ring b, Monad m) => [(a, b)] -> Expr a b -> m b eval m (a:+b) = return (+:) `ap` eval m a `ap` eval m b eval m (a:-b) = return (-:) `ap` eval m a `ap` eval m b eval m (a:*b) = return (*:) `ap` eval m a `ap` eval m b eval m (a:=>b) = return (=:>) `ap` eval m a `ap` eval m b eval m (Invert e) = return invert `ap` eval m e eval m (Var v) | Just c <- lookup v m = return c | otherwise = fail $ "Unbound variable: " ++ show v eval _ (Const c) = return c namedProduct :: [(a, [b])] -> [[(a, b)]] namedProduct = foldr (\(v, cs) l -> concatMap (\c -> map ((v, c):) l) cs) [[]] evalAll :: (Eq a, Show a, Ring b) => [b] -> a -> Expr a b -> [[(a, b)]] evalAll range name e = [ vs ++ [(name, either error id $ eval vs e)] | vs <- namedProduct $ zip (vars e) (repeat range) ]D' *Expr> mapM_ print $ evalAll [True, False] 'E' expr [('A',True),('B',True),('C',True),('D',True),('E',True)] [('A',True),('B',True),('C',True),('D',False),('E',False)] [('A',True),('B',True),('C',False),('D',True),('E',True)] [('A',True),('B',True),('C',False),('D',False),('E',False)] [('A',True),('B',False),('C',True),('D',True),('E',True)] [('A',True),('B',False),('C',True),('D',False),('E',False)] [('A',True),('B',False),('C',False),('D',True),('E',False)] [('A',True),('B',False),('C',False),('D',False),('E',False)] [('A',False),('B',True),('C',True),('D',True),('E',True)] [('A',False),('B',True),('C',True),('D',False),('E',True)] [('A',False),('B',True),('C',False),('D',True),('E',True)] [('A',False),('B',True),('C',False),('D',False),('E',True)] [('A',False),('B',False),('C',True),('D',True),('E',True)] [('A',False),('B',False),('C',True),('D',False),('E',True)] [('A',False),('B',False),('C',False),('D',True),('E',True)] [('A',False),('B',False),('C',False),('D',False),('E',True)] :) . showsPrec 9 v showsPrec _ (Invert e) = ('!':) . showsPrec 9 e showsPrec n e@(a:=>b) | n > 5 = paren $ showsPrec 0 e | otherwise = showsPrec 7 a . ('=':) . ('>':) . showsPrec 5 b showsPrec n e@(a:*b) | n > 7 = paren $ showsPrec 0 e | otherwise = showsPrec 7 a . ('*':) . showsPrec 7 b showsPrec n e | n > 6 = paren $ showsPrec 0 e showsPrec _ (a:+b) = showsPrec 6 a . ('+':) . showsPrec 6 b showsPrec _ (a:-b) = showsPrec 6 a . ('-':) . showsPrec 6 b vars :: (Eq a) => Expr a b -> [a] vars (a:+b) = vars a ++ vars b vars (a:-b) = vars a ++ vars b vars (a:*b) = vars a ++ vars b vars (a:=>b) = vars a ++ vars b vars (Invert e) = vars e; vars (Var v) = [v]; vars _ = [] eval :: (Eq a, Show a, Ring b, Monad m) => [(a, b)] -> Expr a b -> m b eval m (a:+b) = return (+:) `ap` eval m a `ap` eval m b eval m (a:-b) = return (-:) `ap` eval m a `ap` eval m b eval m (a:*b) = return (*:) `ap` eval m a `ap` eval m b eval m (a:=>b) = return (=:>) `ap` eval m a `ap` eval m b eval m (Invert e) = return invert `ap` eval m e eval m (Var v) | Just c <- lookup v m = return c | otherwise = fail $ "Unbound variable: " ++ show v eval _ (Const c) = return c namedProduct :: [(a, [b])] -> [[(a, b)]] namedProduct = foldr (\(v, cs) l -> concatMap (\c -> map ((v, c):) l) cs) [[]] evalAll :: (Eq a, Show a, Ring b) => [b] -> a -> Expr a b -> [[(a, b)]] evalAll range name e = [ vs ++ [(name, either error id $ eval vs e)] | vs <- namedProduct $ zip (vars e) (repeat range) ]基本的评估非常简单:
要生成真值表,您首先必须找到表达式中的所有变量,然后为这些变量生成所有可能的赋值。 使用已经实现的
evaluate
函数可以轻松确定这些赋值的真值:如果您想探索标准库的黑暗角落,您还可以编写一个
Read
用于轻松输入 LogicExpr 的实例:并且可以漂亮地打印真值表:
可以像这样生成所有真值表:
The basic
evaluate
is pretty straight forward:To generate a truth table, you first have to find all the variables in an expression and then generate all the possible assignments for these variables. The truth values of these assignments can easily be determined with the already implemented
evaluate
function:If you want to explore the dark corners of the standard library, you can also write a
Read
instance for easy input ofLogicExpr
s:And truth tables can be printed prettily:
All together truth tables can be generated like this: