问题 Haskell函数,它将可变参数函数作为参数(并返回除func之外的其他内容),而不使用FlexibleInstances,纯Haskell2010


是否有可能表达以下Haskell程序 没有FlexibleInstances,即纯粹的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)]

这是受到答案的启发 如何编写一个以可变函数作为参数的Haskell函数

我怀疑问题是,那 truth 返回除了作为参数的函数之外的其他东西(返回 Bool不是 [Bool])。

这个片段的目的是给出一个布尔函数的所有可能配置的所有评估的列表,即

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

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

最后,要打印一个真值表,如下所示(参见本文末尾的样板,看看产生这个的代码):

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

以下是一些用于测试和可视化的样板代码,该功能的用途是:

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

8135
2017-12-04 12:56


起源



答案:


没问题:

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

如果你愿意,你甚至可以制作“荣誉布尔”,比如整数0和1等。


12
2017-12-04 14:30



啊,谢谢。我在Text.Printf中看到了与IsChar类似的“诡计”......真是太棒了! - scravy


答案:


没问题:

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

如果你愿意,你甚至可以制作“荣誉布尔”,比如整数0和1等。


12
2017-12-04 14:30



啊,谢谢。我在Text.Printf中看到了与IsChar类似的“诡计”......真是太棒了! - scravy


Haskell98的方法是使用newtypes([] Bool)和(( - >)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)]

然后这部分编译而不需要任何LANGUAGE扩展。但它消除了使“真相”变得简单易用的用例。


1
2017-12-04 13:07



为了让其他读者清楚,FlexibleInstances是类型系统的安全扩展。 GHC的文档是 haskell.org/ghc/docs/latest/html/users_guide/... - Chris Kuklewicz
我问过这个问题: stackoverflow.com/questions/8367423/...但是我对没有扩展的解决方案感兴趣。 - scravy