2

是否有一种算法可以引导给定数量的三值逻辑值的所有可能组合?

例如,F(2)应该返回这个列表:

t t
t u
t f
u t
u u
u f
f t
f u
f f

该函数看起来像这样(在 Haskell 中):

data Tril = FALSE | NULL | TRUE

all :: Int -> [[Tril]]
all amount = ???

all1 :: [Tril]
all1 = join (all 1)

all2 :: [(Tril, Tril)]
all2 = map (\[f, s] -> (f, s)) (all 2)

all3 :: [(Tril, Tril, Tril)]
all3 = map (\[f, s, t] -> (f, s, t)) (all 3)
4

2 回答 2

7

您可以非常简单地作为列表理解来执行此操作:

all2 = [ (v1, v2) | v1 <- [FALSE, TRUE, NULL], v2 <- [FALSE, TRUE, NULL] ]

您可以将其等效地编写为一元 do-block:

all2 = do
  v1 <- [FALSE, TRUE, NULL]
  v2 <- [FALSE, TRUE, NULL]
  return (v1, v2)

这给了我们一个关于如何编写可变大小的想法:

all 0 = [[]] -- Note: Empty list with one empty item.
all n = do
  v  <- [FALSE, TRUE, NULL]
  vs <- all (n-1)
  return (v:vs)

事实证明——这有点令人费解——这是replicateM函数的净效应。它需要一个单子动作,执行 N 次,然后将结果收集在一起。

all n = replicateM n [FALSE, TRUE, NULL]
于 2015-03-03T10:16:42.173 回答
4

replicateM正是这样做的:

> import Control.Monad
> replicateM 2 [1,2,3]
[[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3]]

因此,

all :: Int -> [[Tril]]
all amount = replicateM amount [FALSE,NULL,TRUE]

我建议选择另一个名字,因为all已经被Prelude.all.

于 2015-03-03T10:07:45.573 回答