Haskell 长度和滤波器确定线的凸度或凹度

Posted

技术标签:

【中文标题】Haskell 长度和滤波器确定线的凸度或凹度【英文标题】:Haskell length and filter to determine convexity or concavity of a line 【发布时间】:2019-10-01 15:11:51 【问题描述】:

我正在阅读 Real World Haskell,尝试使用 ghc online 解决 Ch3, Q10。

到目前为止,我有以下代码:

data Direction point = MyLeft point | MyRight point | Straight deriving (Show)

getDirectionFromTriple :: Direction p -> Direction p -> Direction p -> Direction p
getDirectionFromTriple p1 p2 p3 
  | (length . filter (== MyLeft) [p1, p2, p3]) > 1 = MyLeft p3
  | (length . filter (== MyRight) [p1, p2, p3]) > 1 = MyRight p3
  | otherwise = Straight

我在尝试编译此代码时收到以下错误(仅发布部分,相同的错误弹出多次):

[1 of 1] Compiling Main             ( jdoodle.hs, jdoodle.o )


jdoodle.hs:17:15: error:
    * Couldn't match expected type `a0 -> t0 a1'
                  with actual type `[point0 -> Direction point0]'
    * Possible cause: `filter' is applied to too many arguments
      In the second argument of `(.)', namely
        `filter (== MyLeft) [p1, p2, p3]'
      In the first argument of `(>)', namely
        `(length . filter (== MyLeft) [p1, p2, p3])'
      In the expression: (length . filter (== MyLeft) [p1, p2, p3]) > 2
   |
17 |   | (length . filter (== MyLeft) [p1, p2, p3]) > 2 = MyLeft p3
   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

jdoodle.hs:17:35: error:
    * Couldn't match expected type `point0 -> Direction point0'
                  with actual type `Direction p'
    * In the expression: p1
      In the second argument of `filter', namely `[p1, p2, p3]'
      In the second argument of `(.)', namely
        `filter (== MyLeft) [p1, p2, p3]'
    * Relevant bindings include
        p3 :: Direction p (bound at jdoodle.hs:16:30)
        p2 :: Direction p (bound at jdoodle.hs:16:27)
        p1 :: Direction p (bound at jdoodle.hs:16:24)
        getDirectionFromTriple :: Direction p
                                  -> Direction p -> Direction p -> Direction p
          (bound at jdoodle.hs:16:1)
   |
17 |   | (length . filter (== MyLeft) [p1, p2, p3]) > 2 = MyLeft p3
   |                                   ^^

jdoodle.hs:17:39: error:
    * Couldn't match expected type `point0 -> Direction point0'
                  with actual type `Direction p'
    * In the expression: p2
      In the second argument of `filter', namely `[p1, p2, p3]'
      In the second argument of `(.)', namely
        `filter (== MyLeft) [p1, p2, p3]'
    * Relevant bindings include
        p3 :: Direction p (bound at jdoodle.hs:16:30)
        p2 :: Direction p (bound at jdoodle.hs:16:27)
        p1 :: Direction p (bound at jdoodle.hs:16:24)
        getDirectionFromTriple :: Direction p
                                  -> Direction p -> Direction p -> Direction p
          (bound at jdoodle.hs:16:1)
   |
17 |   | (length . filter (== MyLeft) [p1, p2, p3]) > 2 = MyLeft p3
   |                                       ^^

我将不胜感激有关如何修复我的代码的建议或有关从三点确定主要方向的更简洁解决方案的建议。

【问题讨论】:

其他错误:因为p3 :: Direction pMyLeft p3 :: Direction (Direction p),这是错误的类型。 旁白:length xs > 1 遍历了xs 的整个脊椎,因为Int 是严格的;在这里没关系,但如果 length xs 预计很大(或无限),那么您可以使用例如 not (small xs) where small = null . drop 1 来提高效率 【参考方案1】:

您可以创建函数来告诉您是右还是左,而不是使用==

import Data.List 

data Direction point = MyLeft point | MyRight point | Straight deriving (Show)

getDirectionFromTriple :: Direction p -> Direction p -> Direction p -> Direction p
getDirectionFromTriple p1 p2 p3 
  | isDirection isLeft  [p1, p2, p3]  = MyLeft (getValue p3)
  | isDirection isRight [p1, p2, p3]  = MyRight (getValue p3)
  | otherwise = Straight

isDirection :: (Direction p -> Bool) -> [Direction p] -> Bool
isDirection f ps = (length . filter f) ps > 1

getValue (MyLeft a) = a
getValue (MyRight a) = a
getValue Straight  = error "No value in Straight"

isLeft  (MyLeft _)  = True
isLeft   _          = False
isRight (MyRight _) = True
isRight  _          = False

main = do
  putStrLn $ show $ getDirectionFromTriple (MyRight 2) Straight (MyLeft 1)
  putStrLn $ show $ getDirectionFromTriple (MyRight 2) (MyRight 3) (MyLeft 1)
  putStrLn $ show $ getDirectionFromTriple (MyLeft 1) (MyLeft 1) (MyRight 2) 

【讨论】:

【参考方案2】:

与最近的问题Why does odd.fst not work with the filter function? 相同。当你写

length . filter f xs

这被解析为

length . (filter f xs)

这显然是不对的:filter f xs 是一个列表,而不是一个函数,所以用length 组合它是没有意义的。相反,你可以写

(length . filter f) xs

虽然更流行的拼写方式是

length . filter f $ xs

【讨论】:

以下都不能避免上述错误: (length .filter (== MyLeft) $ [p1, p2, p3]) (length . filter (== MyLeft) [p1, p2, p3 ]) ((length .filter (== MyLeft)) [p1, p2, p3]) (length $ filter (== MyLeft) [p1, p2, p3]) 这些建议修复了您的第一个类型错误,但不是第二个((== MyLeft) 本身不是一个很好的功能)。

以上是关于Haskell 长度和滤波器确定线的凸度或凹度的主要内容,如果未能解决你的问题,请参考以下文章

修改多段线的凸度

确定线是不是与 CGRect 相交

使用顶点着色器确定线的方向

傅里叶空间滤波

变步长LMS自适应滤波算法的MATLAB程序

python中怎么生成基于窗函数的fir滤波器