Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell function that takes a variadic function as an argument (and returns something else than that func) without FlexibleInstances, pure Haskell2010

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
like image 443
scravy Avatar asked Dec 04 '11 12:12

scravy


2 Answers

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.

like image 145
augustss Avatar answered Sep 30 '22 19:09

augustss


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.

like image 33
Chris Kuklewicz Avatar answered Sep 30 '22 18:09

Chris Kuklewicz