2015-04-28 38 views
1

我编写了这样的代码,但编译时声称“xx不在范围内”时出错。为什么我会得到这个haskell代码的“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 [email protected](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 

看来,如果我不“T使用where条款,我不得不使用深度嵌套的,如果是这样的:

nthElement :: (Ord b)=>(a->b)->Int->[a]->[a] 
nthElement _ _ [] = [] 
nthElement _ _ [x] = [x] 
nthElement op k [email protected](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 

所以,我怎么会改变我的代码来修复错误编译以及使用嵌套如果avoide?

+5

把它看作是{{xx = 2 * x in result}其中{result = replicate xx 3}''。大括号显示范围。你可以做'let {xx = 2 * x;结果=复制xx 3}结果中,无论如何都会更容易阅读。 – bheklilr

+0

在[haskellWiki](https://wiki.haskell.org/Let_vs._Where)上有一篇非常好的文章解释 – Carsten

+0

@bheklilr你应该让它成为答案,因为它是问题的答案(标题在laest)。 – mb14

回答

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条款覆盖了函数体的整个定义,只能使用外部定义的名称函数体(其自变量为testtest本身)。解决此问题的最佳方法是将所有定义移至letwhere。对于你的情况,你可能会想将它们都移动到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 [email protected](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 [email protected](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是懒惰的,因此在实际使用该值之前,您也不必担心计算任何事情。

+0

非常酷! – Alaya

1
nthElement :: (Ord b)=>(a->b)->Int->[a]->[a] 
nthElement _ _ [] = [] 
nthElement _ _ [x] = [x] 
nthElement op k [email protected](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 
相关问题