从Prolog和Haskell中思考 - 生成真值组合列表

时间:2014-05-07 07:24:44

标签: haskell prolog combinations list-comprehension translate

我知道一些Prolog并且刚开始在Haskell进行一些自学。我一直在研究99 Problems for Haskell,一路上学习并真正享受Haskell。有时候,我试图通过在Prolog中编写代码来解释我对问题空间的理解,然后思考该解决方案如何与Haskell中的函数方法相关联。今晚,在处理逻辑问题(问题47和48)时,我分心试图完成构建一个包含n值的所有真值组合列表的简单任务。我想要一个函数tValues :: Int -> [[Bool]]。这个问题可以在Prolog中以非常简单和声明的方式解决,例如:

combinations_of_n_truth_values(N, AllValues) :-
    findall(Values, n_truth_values(N, Values), AllValues).

n_truth_values(N, TruthValues) :-
    length(TruthValues, N),
    maplist(truth_value, TruthValues).

truth_value(true).
truth_value(false).

使用时,变量AllValues将与所需的真值列表列表统一。我想知道一位经验丰富的Haskell程序员将如何解决同样的问题。我希望有一个同样简单明了的解决方案,但我似乎无法以正确的方式使我的Haskell大脑正常运作。

我使用列表推导来摆弄一些半类似物,如下所示:

tValues:: Int -> [[Bool]]
tValues 0 = []
tValues n = [v:vs | v  <- tValue
                  , vs <- tValues (n-1) ] 

tValue :: [Bool]
tValue = [True, False]

tValues仅返回[]。我想我只需要一些人与人之间的互动来帮助我清醒一下,并且可以让我更深入地了解我。

非常感谢。

4 个答案:

答案 0 :(得分:9)

在伪代码中,你的列表理解

[v:vs | v  <- tValue
      , vs <- tValues (n-1) ] 

等于

for any combination of two elements in `tValue`  and `tValues (n-1)`
    cons the first onto the latter

但是,tValues没有元素可以开头,它是一个空列表。让我们为n = 1

模拟这个
tValues 1 = [v:vs | v  <- tValue
                  , vs <- tValues 0 ] 
          = [v:vs | v  <- [True, False]
                  , vs <- [] ] 
            -- since there is no vs
          = []

这会在整个递归过程中传播。解决方案非常简单:更改基本案例以包含空组合:

tValues 0 = [[]] -- or: return []

现在模拟产生:

tValues 1 = [v:vs | v  <- tValue
                  , vs <- tValues 0 ] 
          = [v:vs | v  <- [True, False]
                  , vs <- [[]]] 
            -- vs is []
          = [True:[],False:[]]
          = [[True],[False]]

这正是我们想要的。

答案 1 :(得分:6)

使用列表monad,

g n = mapM (\_-> [True, False]) [1..n]

关于你的功能的基本情况。当函数返回一个包含长度为n 的所有真值列表的列表时,对于n=0,它应该返回一个包含所有真值列表的列表长度为0 ,即包含一个空列表的列表。

答案 2 :(得分:4)

truths :: [[Bool]]
truths = [True] : [False] : concatMap (\bs -> [True:bs, False:bs]) truths

truthValues :: Int -> [[Bool]]
truthValues n = dropWhile ((< n) . length) . takeWhile ((<= n) . length) $ truths

truths是所有真值组合的无限列表,因为长度单调增加我们可以只取列表的前面部分,而长度小于或等于我们正在寻找的集合因为,然后放下长度较短的前面。

您只获得空列表的原因是最终tValues (n-1)评估为tValues 0,这当然是空列表。尝试从列表推导中的空列表中绘制会导致迭代失败。这传播了理解链。将基本案例更改为tValues 1 = [[True], [False]],它将起作用。

答案 3 :(得分:4)

本身并不是一个完整的答案,但如果您感兴趣,请使用列表monad:

truthValues ∷ Int → [[Bool]]
truthValues 0 = return []
truthValues n = truthValues (n - 1) >>= (\l → [True:l, False:l])

truthValues n = foldM (\l _ -> [True:l, False:l]) [] [1..n]

truthValues = flip replicateM [True, False]

另请参阅Will Ness的回答及附上的评论:)