2011-12-04 17 views
11

olmadan argüman olarak değişken bir işlevi alan ve bu fonksiyondan bir değişkenlik fonksiyonunu alan Haskell işlevi, aşağıdaki Haskell programı Esnek Insansız, yani saf Haskell2010 olmadan ifade edilebilir mi?Esnek Değişkenler, saf 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)] 

Bu, How to write a Haskell function that takes a variadic function as an argument numaralı yanıttan esinlenmiştir.

Sorun şu ki, truth, argüman olarak aldığı işlevden başka bir şey döndürüyor (Bool, [Bool] değil).

bu pasajı amacı, örneğin, Sonunda

Main> truth (\x y -> x && y) 
[True,False,False,False] 

Main> truth (\x y -> x || y) 
[True,True,True,False] 

bir Boole için gerekli tüm muhtemel konfigürasyonunun bütün değerlendirmelerin bir listesini elde etmek üzere, yani bir gerçeği tablo, bu gibi basılacak test ve görülebilir hale getirilebilmesi için bir kazan plaka kodu Bu fonksiyon, ne olduğu burada

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 

: (bu üretim kodu görmek için bu yazının sonunda kazan etiketine bakınız)

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 

cevap

12

Sorun: İsterseniz

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 

Hatta 0 ve 1 ile tamsayı gibi, 'fahri Boolean' yapabilir vb

+0

Aah, teşekkürler. Text.Printf'de IsChar ile benzer bir "hile" gördüm ... darn! – scravy

1

Haskell98 yolu ([] BOOL) ve için newtypes kullanmaktır ((->) 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)] 

Bu kısım daha sonra ihtiyaç duyulan herhangi bir dil uzantıları derler. Ancak, 'hakikat' ile çalışmanın basitliğini kullanma olgusunu ortadan kaldırır.

+0

diğer okuyuculara Açık olmak gerekirse, FlexibleInstances güvenli bir uzantısıdır tip sistemi. GHC'ye ait belgeler http://www.haskell.org/ghc/docs/latest/html/users_guide/type-class-extensions.html#instance-rules –

+1

adresinde şu şekilde sorulmuştur: http://stackoverflow.com/questions/8367423/is-haskell-flexibleinstances-a-stable-extension-to-the-language, ancak uzantıları olmayan bir çözüm ile ilgilendi. – scravy