标准库函数,代码重用。此外,您的括号使用和间距真的很奇怪。
evaluate (V a) l =
case lookup a l
of Just x -> x
Nothing -> error $ "Unbound variable: " ++ show a
evaluate (V a) l = maybe (error $ "Unbound variable: " ++ show a) id $ lookup a l
evaluate (Negation a) l = not $ evaluate a l
evaluate (Implication a b) l = evaluate (Negation a `Disjunction` b) l
现在,你想要一个
generateTruthTable
吗?那很容易,只需取布尔变量的所有可能状态,并将评估的表达式附加到每个状态的末尾即可。
generateTruthTable :: [Variable] -> LogicExpr -> [[(Variable, Bool)]]
generateTruthTable vs e = [l ++ [('E', evaluate e l)] | l <- allPossible vs]
如果你有一个可以生成所有可能状态的函数,那该多好啊。
allPossible :: [Variable] -> [[(Variable, Bool)]]
根据我的直觉,这似乎应该是一个catamorphism。毕竟,它需要查看列表中的所有内容,但返回的是一个不同结构的东西,而且它可能可以简单地分解,因为这是一门入门级的计算机科学课程。(我不在乎课程编号是什么,这是入门级的东西。)
allPossible = foldr step initial where
step v ls = ???
现在,foldr :: (a -> b -> b) -> b -> [a] -> b
,所以前两个参数必须是step :: a -> b -> b
和initial :: b
。现在,allPossible :: [Variable] -> [[(Variable, Bool)]] = foldr step initial :: [a] -> b
。嗯,这一定意味着a = Variable
和b = [[(Variable, Bool)]]
。那么对于step
和initial
来说意味着什么呢?
step :: Variable -> [[(Variable, Bool)]] -> [[(Variable, Bool)]]
initial :: [[(Variable, Bool)]]
有趣。不知何故,需要一种方法从变量状态列表中“步进”,并向其中添加一个单独的变量,以及一些完全没有变量的初始列表。
如果你的思维已经成功地转换到函数式编程范式中,这应该已经足够。如果没有,无论你在这里得到了什么指导,几个小时后作业就要交了,你基本上是没救了。祝好运,如果作业提交后仍然卡住了,你应该问你的教授或者在这里提出非紧急问题。
如果您在使用语言时遇到基本的可用性问题(“什么是语法”,“运行时语义是什么”,“是否有预先存在的
xxx功能”等):
我希望您的课程提供了类似的资源,但如果没有,以上所有内容都可以通过谷歌搜索轻松发现。
如果有适当的参考资料,任何值得自己的salt程序员应该能够在几个小时内掌握任何新语言的语法,并在几天内对运行时有一个工作理解。当然,掌握新范式可能需要很长时间,而且对学生施加相同的标准有点不公平,但这就是班级的目的。
在Stack Overflow上提出关于更高级问题的问题可能会得到较少的答案,但也会受到远少于其他问题的恶意:) 在大多数人眼中,作业问题被归类为“替我做我的工作!”。
剧透
请勿作弊。但是,为了让您体验Haskell可以实现多么棒的功能...
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
{-# LANGUAGE OverlappingInstances, PatternGuards #-}
module Expr (Ring(..), (=:>), Expr(..), vars, eval, evalAll) where
import Control.Monad.Error
infixl 5 =:>, :=>
infixl 6 +:, -:, :+, :-
infixl 7 *:, :*
class (Eq a) => Ring a where
(+:) :: a -> a -> a; (-:) :: a -> a -> a; x -: y = x +: invert y
(*:) :: a -> a -> a; invert :: a -> a; invert x = zero -: x
zero :: a; one :: a
(=:>) :: (Ring a) => a -> a -> a
(=:>) = flip (-:)
instance (Num a) => Ring a where
(+:) = (+); (-:) = (-); (*:) = (*)
invert = negate; zero = 0; one = 1
instance Ring Bool where
(+:) = (||); (*:) = (&&)
invert = not; zero = False; one = True
data Expr a b
= Expr a b :+ Expr a b | Expr a b :- Expr a b
| Expr a b :* Expr a b | Expr a b :=> Expr a b
| Invert (Expr a b) | Var a | Const b
paren :: ShowS -> ShowS
paren ss s = '(' : ss (')' : s)
instance (Show a, Show b) => Show (Expr a b) where
showsPrec _ (Const c) = ('@':) . showsPrec 9 c
showsPrec _ (Var v) = ('$':) . 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)
]
$ ghci
GHCi,版本6.10.2:http://www.haskell.org/ghc/ :? 获取帮助
加载包ghc-prim...链接...完成。
加载包整数...链接...完成。
加载包基础...链接...完成。
Prelude> :l Expr.hs
[1 of 1] Compiling Expr ( Expr.hs, interpreted )
好的,模块已加载:Expr。
*Expr> mapM_ print . evalAll [1..3] 'C' $ Var 'A' :* Var 'B'
加载包mtl-1.1.0.2...链接...完成。
[('A',1),('B',1),('C',1)]
[('A',1),('B',2),('C',2)]
[('A',1),('B',3),('C',3)]
[('A',2),('B',1),('C',2)]
[('A',2),('B',2),('C',4)]
[('A',2),('B',3),('C',6)]
[('A',3),('B',1),('C',3)]
[('A',3),('B',2),('C',6)]
[('A',3),('B',3),('C',9)]
*Expr> 让expr = Var 'A' :=> (Var 'B' :+ Var 'C') :* Var 'D'
*Expr> expr
$'A'=>($'B'+$'C')*$'D'
*Expr> mapM_ print $ evalAll [True, False] 'E' expr
[('A',真实的),('B',真实的),('C',真实的),('D',真实的),('E',真实的)]
[('A',真实的),('B',真实的),('C',真实的),('D',假的),('E',假的)]
[('A',真实的),('B',真实的),('C',假的),('D',真实的),('E',真实的)]
[('A',真实的),('B',真实的),('C',假的),('D',假的),('E',假的)]
[('A',真实的),('B',假的),('C',真实的),('D',真实的),('E',真实的)]
[('A',真实的),('B',假的),('C',真实的),('D',假的),('E',假的)]
[('A',真实的),('B',假的),('C',假的),('D',真实的),('E',假的)]
[('A',真实的),('B',假的),('C',假的),('D',假的),('E',假的)]
[('A',假的),('B',真实的),('C',真实的),('D',真实的),('E',真实的)]
[('A',假的),('B',真实的),('C',真实的),('D',假的),('E',真实的)]
[('A',假的),('B',真实的),('C',假的),('D',真实的),('E',真实的)]
[('A',假的),('B',真实的),('C',假的),('D',假的),('E',真实的)]
[('A',假的),('B',假的),('C'