is it possible to express the following Haskell program without FlexibleInstances, i.e. in pure Haskell2010?
{-# LANGUAGE FlexibleInstances #-}
class Funk a where truth :: a -> [Bool]
instance Funk [Bool] where truth = \x -> x
instance Funk Bool where truth = \x -> [x]
instance Funk b => Funk (Bool -> b) where
truth f = concat [truth (f True), truth (f False)]
This is inspired by the answer on How to write a Haskell function that takes a variadic function as an argument.
I suspect the problem is, that truth
returns something else than the function which it takes as an argument (which returns Bool
, not [Bool]
).
The purpose of this snippet is, to give a list of all evaluations of all possible configuration for a boolean function, i.e.
Main> truth (\x y -> x && y)
[True,False,False,False]
Main> truth (\x y -> x || y)
[True,True,True,False]
In the end, a truth-table is to be printed, like this (see boiler-plate at the end of this post to see the code which produces this):
Main> main
T T T | T
T T F | T
T F T | T
T F F | F
F T T | T
F T F | F
F F T | T
F F F | T
Here is some boiler-plate code for testing and visualizing, what the purpose of this function is:
class TruthTable a where
truthTable :: Funk f => f -> a
instance TruthTable [String] where
truthTable f = zipWith (++) (hCells (div (length t) 2)) (map showBool $ truth f)
where
showBool True = "| T"
showBool False = "| F"
hCells 1 = ["T ", "F "]
hCells n = ["T " ++ x | x <- hCells (div n 2)] ++ ["F " ++ x | x <- hCells (div n 2)]
instance TruthTable [Char] where
truthTable f = foldl1 join (truthTable f)
where join a b = a ++ "\n" ++ b
instance TruthTable (IO a) where
truthTable f = putStrLn (truthTable f) >> return undefined
main :: IO ()
main = truthTable (\x y z -> x `xor` y ==> z)
xor :: Bool -> Bool -> Bool
xor a b = not $ a == b
(==>) :: Bool -> Bool -> Bool
a ==> b = not $ a && not b
No problem:
class Funk a where truth :: a -> [Bool]
instance (IsBool a) => Funk [a] where truth = map toBool
instance Funk Bool where truth = \x -> [x]
instance (IsBool a, Funk b) => Funk (a -> b) where
truth f = concat [truth (f $ fromBool True), truth (f $ fromBool False)]
class IsBool a where
toBool :: a -> Bool
fromBool :: Bool -> a
instance IsBool Bool where
toBool = id
fromBool = id
You can even make 'honorary booleans' if you wish, like Integer with 0 and 1 etc.
The Haskell98 way is to use newtypes for ([] Bool) and ((->) Bool b):
newtype LB = LB [Bool]
newtype FAB b = FAB (Bool -> b)
class Funk a where truth :: a -> [Bool]
instance Funk LB where truth = \(LB x) -> x
instance Funk Bool where truth = \x -> [x]
instance Funk b => Funk (FAB b) where
truth (FAB f) = concat [truth (f True), truth (f False)]
This part then compiles without needed any LANGUAGE extensions. But it eliminates the use case of making 'truth' simple to work with.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With