我编写了这样的代码,但在编译说" xx不在范围"时会出错。
test x =
let xx = 2 * x
in result
where result = replicate xx 3
我知道我可以使用in replicate xx 3
修复它,但是,上面的代码只是一个演示,我正在处理的真实代码如下:
nthElement :: (Ord b)=>(a->b)->Int->[a]->[a]
nthElement _ _ [] = []
nthElement _ _ [x] = [x]
nthElement op k vals@(x:xs)
| k > (length vals) = vals
| otherwise = let left = [p | p<-vals, (op p) < (op x)]
midd = [p | p<-vals, (op p) == (op x)]
right = [p | p<-vals, (op p) > (op x)]
leftLen = length left
middLen = length midd
in result where result | leftLen >= k = (nthElement op k left) ++ midd ++ right
| (leftLen + middLen) >= k = left ++ midd ++ right
| otherwise = left ++ midd ++ nthElement op (k-middLen-leftLen) right
似乎如果我不使用where
子句,我必须使用深层嵌套,如下所示:
nthElement :: (Ord b)=>(a->b)->Int->[a]->[a]
nthElement _ _ [] = []
nthElement _ _ [x] = [x]
nthElement op k vals@(x:xs)
| k > (length vals) = vals
| otherwise = let left = [p | p<-vals, (op p) < (op x)]
midd = [p | p<-vals, (op p) == (op x)]
right = [p | p<-vals, (op p) > (op x)]
leftLen = length left
middLen = length midd
in if leftLen >= k
then (nthElement op k left) ++ midd ++ right
else if (leftLen + middLen) >= k
then left ++ midd ++ right
else left ++ midd ++ nthElement op (k-middLen-leftLen) right
那么,我怎么能改变我的代码来修复编译错误以及避免使用嵌套的if?
答案 0 :(得分:3)
您应该将此代码更多地视为
test x = {
let {
xx = 2 * x
} in {
result
}
} where {
result = replicate xx 3
}
而不是
test x = {
let {
xx = 2 * x
} in {
result where {
result = replicate xx 3
}
}
}
where
子句涵盖函数体的整个定义,并且只能使用在函数体外定义的名称(test
和test
本身的参数)。解决此问题的最佳方法是将所有定义移至let
或where
。对于您的情况,您可能希望将它们全部移动到let
:
test x =
let xx = 2 * x
result = replicate xx 3
in result
或者您的实际使用案例:
nthElement :: (Ord b) => (a -> b) -> Int -> [a] -> [a]
nthElement _ _ [] = []
nthElement _ _ [x] = [x]
nthElement op k vals@(x:xs)
| k > (length vals) = vals
| otherwise = let left = [p | p<-vals, (op p) < (op x)]
midd = [p | p<-vals, (op p) == (op x)]
right = [p | p<-vals, (op p) > (op x)]
leftLen = length left
middLen = length midd
result | leftLen >= k = (nthElement op k left) ++ midd ++ right
| (leftLen + middLen) >= k = left ++ midd ++ right
| otherwise = left ++ midd ++ nthElement op (k-middLen-leftLen) right
in result
但是,当这个从页面的侧面行进时,我会稍微重构一下,只使用一个警卫和where
:
nthElement :: (Ord b) => (a -> b) -> Int -> [a] -> [a]
nthElement _ _ [] = []
nthElement _ _ [x] = [x]
nthElement op k vals@(x:xs)
| k > length vals = vals
| k <= leftLen = nth k left ++ midd ++ right
| k <= leftMiddLen = left ++ midd ++ right
| otherwise = left ++ midd ++ nth kR right
where
opx = op x
left = [p | p <- vals, op p < opx]
midd = [p | p <- vals, op p == opx]
right = [p | p <- vals, op p > opx]
leftLen = length left
middLen = length midd
leftMiddLen = leftLen + middLen
nth = nthElement op
kR = k - leftMiddLen
98%这只是风格,你可能不喜欢这种方式,但我觉得它更容易阅读。特别是,我会说2%不仅仅是风格将警卫折叠到一个单一的水平,它使你的意图更清晰。由于Haskell很懒,所以在实际使用该值之前,您也不必担心计算任何东西。
答案 1 :(得分:1)
nthElement :: (Ord b)=>(a->b)->Int->[a]->[a]
nthElement _ _ [] = []
nthElement _ _ [x] = [x]
nthElement op k vals@(x:xs)
| k > (length vals) = vals
| otherwise = let left = [p | p<-vals, (op p) < (op x)]
midd = [p | p<-vals, (op p) == (op x)]
right = [p | p<-vals, (op p) > (op x)]
leftLen = length left
middLen = length midd
result | leftLen >= k = (nthElement op k left) ++ midd ++ right
| (leftLen + middLen) >= k = left ++ midd ++ right
| otherwise = left ++ midd ++ nthElement op (k-middLen-leftLen) right
in result