我知道一些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
仅返回[]
。我想我只需要一些人与人之间的互动来帮助我清醒一下,并且可以让我更深入地了解我。
非常感谢。
答案 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的回答及附上的评论:)