假设我有一个列表推导,它返回一个序列列表,其中所选择的元素彼此依赖(参见下面的示例)。有没有办法(方便地)根据早期计算编程元素的数量及其相关条件?例如,返回类型[[a,b,c]]或[[a,b,c,d,e]]取决于程序中的另一个值?此外,还有其他/更好的方式而不是列表理解来制定相同的想法吗?
(我觉得可能,尽管很麻烦且有限,但要写出一个更大的列表理解来开始并通过添加 s 参数和辅助函数来修剪它,这可能会使一个或多个元素一个值可以在以后轻松过滤,相关条件默认为True。)
s = [[a, b, c, d] | a <- list, someCondition a,
b <- list, b /= a, not (someCondition b),
otherCondition a b,
c <- list, c /= a, c /= b, not (someCondition c),
otherCondition b c,
d <- list, d /= a, d /= b, d /= c,
someCondition d, someCondition (last d),
otherCondition c d]
答案 0 :(得分:4)
这个问题难以理解。
是否有办法(方便地)根据较早的计算对元素数量及其相关条件进行编程?
问题是“程序”在这句话中实际上不是一个可理解的动词,因为人类编程计算机,或编程录像机,但你不能“编程编号”。所以我不明白你在这里想说的是什么。
但我可以给你代码审查,也许通过代码审查,我可以理解你提出的问题。
听起来你正试图通过消除死胡同来解决迷宫。
您的代码实际执行的是:
生成一个非死角或死角附近的单元格列表,名为filtered
从步骤1生成一系列相邻单元格,sequences
将四个这样的相邻序列连接成一条路线。
主要问题:这只有在正确的路线恰好是八个瓷砖长时才有效!试着解决这个迷宫:
[E]-[ ]-[ ]-[ ] | [ ]-[ ]-[ ]-[ ] | [ ]-[ ]-[ ]-[ ] | [ ]-[ ]-[ ]-[ ] | [ ]-[ ]-[ ]-[E]
因此,从代码审查中倒退,听起来像你的问题是:
如果我事先不知道它有多长,我如何生成一个列表?
您可以通过搜索解决迷宫(DFS,BFS,A *)。
import Control.Monad
-- | Maze cells are identified by integers
type Cell = Int
-- | A maze is a map from cells to adjacent cells
type Maze = Cell -> [Cell]
maze :: Maze
maze = ([[1], [0,2,5], [1,3], [2],
[5], [4,6,1,9], [5,7], [6,11],
[12], [5,13], [9], [7,15],
[8,16], [14,9,17], [13,15], [14,11],
[12,17], [13,16,18], [17,19], [18]] !!)
-- | Find paths from the given start to the end
solve :: Maze -> Cell -> Cell -> [[Cell]]
solve maze start = solve' [] where
solve' path end =
let path' = end : path
in if start == end
then return path'
else do neighbor <- maze end
guard (neighbor `notElem` path)
solve' path' neighbor
函数solve
通过深度优先搜索工作。它不是将所有内容都放在一个列表中,而是递归地工作。
要查找从start
到end
的路径,如果start /= end
,
查看与结尾相邻的所有单元格neighbor <- maze end
,
确保我们不会回溯单元格guard (negihbor `notElem` path)
,
尝试查找从start
到neighbor
的路径。
不要试图立刻理解整个函数,只要理解递归的一点。
如果你想找到从单元格0到单元格19的路径,请说明:我们知道单元格18和19是连接的(因为它们是直接连接的),所以我们可以尝试解决从中查找路径的问题单元格0到单元格18。
这是递归。
守卫,
someCondition a == True
相当于,
someCondition a
因此也相当于,
(someCondition a == True) == True
或者,
(someCondition a == (True == True)) == (True == (True == True))
或者,
someCondition a == (someCondition a == someCondition a)
第一个,someCondition a
,很好。
do
符号上例中的do
符号等同于列表推导,
do neighbor <- maze end
guard (neighbor `notElem` path)
solve' path' neighbor
列表推导语法中的等效代码是
[result | neighbor <- maze end,
neighbor `notElem` path,
result <- solve' path' neighbor]
答案 1 :(得分:2)
有没有办法(方便地)根据较早的计算编程元素的数量及其相关条件?例如,返回类型[[a,b,c]]或[[a,b,c,d,e]]取决于程序中的另一个值?
我想你想在类型签名中静态编码列表(或向量)的长度。无法在类型级别检查标准列表的长度。
One approach这样做是为了使用phantom types,并引入将编码不同大小的虚拟数据类型:
newtype Vector d = Vector { vecArray :: UArray Int Float }
-- using EmptyDataDecls extension too
data D1
data D2
data D3
现在你可以创建不同长度的矢量,这些矢量将具有不同的类型:
vector2d :: Float -> Float -> Vector D2
vector2d x y = Vector $ listArray (1,2) [x,y]
vector3d :: Float -> Float -> Float -> Vector D3
vector3d x y z = Vector $ listArray (1,3) [x,y,z]
如果输出的长度取决于输入的长度,则考虑使用type-level arithmetics来参数化输出。 你可以通过谷歌搜索“Haskell静态大小的矢量”找到更多。
更简单的解决方案是使用 固定长度的元组。如果你的函数可以产生3元组或5元组,用Either
数据类型包装它们:`(a,b,c)(a,b,c,d,e)。
答案 2 :(得分:1)
看起来你正试图通过有限域中的唯一选择来解决一些逻辑谜题。请参考以下内容:
这有助于我们的方式,我们在从中挑选时带着我们的域名;下一个选择是从包含前一个选择之后剩下的内容的缩小域中制作的,因此链是自然形成的。 E.g。
p43 = sum [ fromDigits [v0,v1,v2,v3,v4,v5,v6,v7,v8,v9]
| (dom5,v5) <- one_of [0,5] [0..9] -- [0..9] is the
, (dom6,v6) <- pick_any dom5 -- initial domain
, (dom7,v7) <- pick_any dom6
, rem (100*d5+10*d6+d7) 11 == 0
....
-- all possibilities of picking one elt from a domain
pick_any :: [a] -> [([a], a)]
pick_any [] = []
pick_any (x:xs) = (xs,x) : [ (x:dom,y) | (dom,y) <- pick_any xs]
-- all possibilities of picking one of provided elts from a domain
-- (assume unique domains, i.e. no repetitions)
one_of :: (Eq a) => [a] -> [a] -> [([a], a)]
one_of ns xs = [ (ys,y) | let choices = pick_any xs, n <- ns,
(ys,y) <- take 1 $ filter ((==n).snd) choices ]
作为列表理解的一部分,您可以轻松检查答案中的多个元素:
s = [answer | a <- .... , let answer=[....] , length answer==4 ]
或根据条件创建不同的答案,
s = [answer | a <- .... , let answer=if condition then [a,b,c] else [a]]
答案 3 :(得分:1)
您可以用monadic形式编写列表理解(参见guards in Monad Comprehensions):
(解释:monad必须是支持失败的MonadPlus实例。
guard False
使monad无法评估为mzero。后续结果附加了List monad的mplus =(++)。)
import Control.Monad (guard)
myDomain = [1..9] -- or whatever
validCombinations :: [a] -> [[a]]
validCombinations domainList = do
combi <- List.subsequences domainList
case combi of
[a,b] -> do
guard (propertyA a && propertyB b)
return combi
[a,b,c] -> do
guard (propertyA a && propertyB b && propertyC c)
return combi
_ -> guard False
main = do
forM_ (validCombinations myDomain) print
再次更新,递归获取元素,保存组合和检查
import Control.Monad
validCombinations :: Eq a => Int -> Int -> [a] -> [(a -> Bool)] -> [a] -> [[a]]
validCombinations indx size domainList propList accum = do
elt <- domainList -- try all domain elements
let prop = propList!!indx
guard $ prop elt -- some property
guard $ elt `notElem` accum -- not repeated
{-
case accum of
prevElt : _ -> guard $ some_combined_check_with_previous elt prevElt
_ -> guard True
-}
if size > 1 then do
-- append recursively subsequent positions
other <- validCombinations (indx+1) (size-1) domainList propList (elt : accum)
return $ elt : other
else
return [elt]
myDomain = [1..3] :: [Int]
myProps = repeat (>1)
main = do
forM_ (validCombinations 0 size myDomain myProps []) print
where
size = 2
大小为2的结果具有非常重要的结果:
[2,3] [3,2]