Propositional logic implementation

All, Is there some better way to do this? It seems like a lot of boilerplate. Thanks! http://hpaste.org/13807#a1

Look at SYB (Data.Data, Data.Generics.*). For example, your "symbols" function can be rewritten as symbols :: Sentence -> [Symbol] symbols s = nub $ listify (const True) s "true" is not that simple, because this code is NOT boilerplate - each alternative is valuable by itself. On 10 Jan 2009, at 23:56, Andrew Wagner wrote:
All, Is there some better way to do this? It seems like a lot of boilerplate. Thanks!
http://hpaste.org/13807#a1 _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Nice Idea, though I don't know that I want something that extensive. I was
more looking for whether there was a better way I could define the algebraic
data type.
On Sat, Jan 10, 2009 at 6:04 PM, Miguel Mitrofanov
Look at SYB (Data.Data, Data.Generics.*). For example, your "symbols" function can be rewritten as
symbols :: Sentence -> [Symbol] symbols s = nub $ listify (const True) s
"true" is not that simple, because this code is NOT boilerplate - each alternative is valuable by itself.
On 10 Jan 2009, at 23:56, Andrew Wagner wrote:
All,
Is there some better way to do this? It seems like a lot of boilerplate. Thanks!
http://hpaste.org/13807#a1 _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Sunday 11 January 2009 01:44:50 Andrew Wagner wrote:
Nice Idea, though I don't know that I want something that extensive. I was more looking for whether there was a better way I could define the algebraic data type.
Let's have a look at your definitions from http://hpaste.org/13807#a1 :
data Sentence = Atomic Atom | Complex Complex
The distinction between atomic expressions and complex expressions seems to be merely academic: None of your functions actually distinguishes between them. Thus, I suggest that you move the constructors of type Atom and Complex to type Sentence. The only place where type Atom is used is in the following declaration:
newtype Model = Model [Atom]
But a close look at function true :: Model -> Sentence -> Bool reveals that it is sufficient to make a model a list of symbols. Therefore, we modify type Model to type Model = [Symbol] If Symbol was an instance of type class Ord, we could even move from lists to sets: import qualified Data.Set as Set type Model = Set.Set Symbol Then function symbols could also return sets of symbols, allowing for a much more efficient implementation via Set.union instead of List.nub and List.++: symbols :: Sentence -> Set.Set Symbol
data Atom = T | F | Symbol Symbol deriving Eq
In function symbols you need to distinguish between symbols and other values of type Atom. With your current definition, function symbol must evaluate every atom to a concrete truthvalue. We can avoid this by defining Atom as data Atom = Const Bool | Symbol Symbol deriving Eq
data Symbol = A | B | C | P | Q | R | X | Y | Z | Label String deriving Eq
I don't like two things about this definition: 1) There are two kinds of symbols, but there is no clear distinction between them. Instead, String-type labels are modelled as one special case of a symbol. 2) You enumerate characters explicitly. Instead, you could use type Char for single-character symbols. If you define symbols by type Symbol = Either Char String then you have a clear distinction between single-character symbols and labels, and you also get the above-mentioned instance of typeclass Ord for free.
data Complex = Not Sentence | Sentence :/\: Sentence | Sentence :\/: Sentence | Sentence :=>: Sentence | Sentence :<=>: Sentence
There are some opportunities to reduce the number of constructors in this declaration. Constructor :=>: can easily be replaced by a function (==>) :: Sentence -> Sentence -> Sentence a ==> b = Not a :/\: b You can even define true, false, negation, conjunction and disjunction in terms of a newly introduced constructor Nand [Sentence] so that false = Nand [] true = Nand [false] Operator <=> can also be expressed in terms of Nand, but that would lead to duplicated work in function symbol and function true. Thus, we keep constructor :<=>:. The resulting declarations are data Sentence = Nand [Sentence] | Sentence :<=>: Sentence | Symbol Symbol type Symbol = Either Char String type Model = Set.Set Symbol This will reduce your boilerplate code to a minimum. :) Regards, Holger

I like using smart constructors to replace :<=>: and :=>:
a \/ b = a :\/: b
a /\ b = a :/\: b
a ==> b = Not a \/ b
a <=> b = (a ==> b) /\ (b ==> a)
Also, if you generalize Sentence a bit you get a really nice
formulation of "true". See my paste at http://hpaste.org/13807#a2
-- ryan
2009/1/10 Andrew Wagner
Nice Idea, though I don't know that I want something that extensive. I was more looking for whether there was a better way I could define the algebraic data type.
On Sat, Jan 10, 2009 at 6:04 PM, Miguel Mitrofanov
wrote: Look at SYB (Data.Data, Data.Generics.*). For example, your "symbols" function can be rewritten as
symbols :: Sentence -> [Symbol] symbols s = nub $ listify (const True) s
"true" is not that simple, because this code is NOT boilerplate - each alternative is valuable by itself.
On 10 Jan 2009, at 23:56, Andrew Wagner wrote:
All, Is there some better way to do this? It seems like a lot of boilerplate. Thanks!
http://hpaste.org/13807#a1 _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
participants (4)
-
Andrew Wagner
-
Holger Siegel
-
Miguel Mitrofanov
-
Ryan Ingram