haskell中的天际线,可能导致'function'应用于太少的参数

时间:2016-03-25 09:12:04

标签: haskell

我正在为大学学习哈斯克尔,我正试图做一个天际线问题 - > https://briangordon.github.io/2014/08/the-skyline-problem.html

我的haskell语法存在严重问题,因为我来自OO语言,FP对我来说很奇怪,所以,这是我目前的代码:

    type Edificio = (Int,Int,Int)
type Coordenada = (Int,Int)
type Skyline = [Coordenada]

resuelveSkyline :: [Edificio] -> Skyline
resuelveSkyline [] = []
resuelveSkyline [x] = edificioAskyline(x)
resuelveSkyline xs = combina (resuelveSkyline(fst(divide(xs))),resuelveSkyline(snd(divide(xs))))

edificioAskyline :: Edificio -> Skyline
edificioAskyline (x1,x2,h) = [(x1,h),(x2,0)]

divide :: [Edificio] -> ([Edificio], [Edificio])
divide edificios = splitAt (((length edificios) + 1) `div` 2) edificios

combina :: Skyline -> Skyline -> Skyline
combina (_,_) = []

我有两个问题,第一个是:

我有一个类型Coordenada例如,如果我想传递一个Coordenada作为其他函数的参数并且在其中获得他的第一个元组值,我该怎么办?

第二个是,编译时遇到这个错误:

 Main.hs:8:22:
    Couldn't match type ‘Skyline -> Skyline’ with ‘[Coordenada]’
    Expected type: Skyline
      Actual type: Skyline -> Skyline
    Probable cause: ‘combina’ is applied to too few arguments
    In the expression:
      combina
        (resuelveSkyline (fst (divide (xs))), 
         resuelveSkyline (snd (divide (xs))))
    In an equation for ‘resuelveSkyline’:
        resuelveSkyline xs
          = combina
              (resuelveSkyline (fst (divide (xs))), 
               resuelveSkyline (snd (divide (xs))))

我知道合并还没有完成,但我想尝试一点一点地做。

我用西班牙语,因为我必须强制使用这些功能名称(教授责成我们)。 我将解释每种方法。

resuelveSkyline作为输入列出了Edificio并返回一个Skyline,它的主要功能。 edificioASkyline将建筑物作为输入并将其转换为天际线 divide获取一个列表并返回相同大小的2个列表。 combina需要2个天际线并返回一个与之合并的新天际线。

1 个答案:

答案 0 :(得分:2)

我们假设你要定义func :: A -> B -> C。定义func的语法是:

func :: A -> B -> C
func a b = ...
  -- ^^^

但是,如果您使用(a,b),则不会使用两个单独的参数,而是使用一对:

--      vvvvv
func :: (A,B) -> C
func (a,b) = ...
--   ^^^^^

但是,GHC仅在此行中查找combina的类型签名:

resuelveSkyline xs = combina (resuelveSkyline(fst(divide(xs))),resuelveSkyline(snd(divide(xs))))

因此,虽然您已定义combina来处理元组,但它不会键入check。请注意,combina's定义也不会与其声明的类型统一。

话虽如此,如果您更改combina的类型并引入帮助程序,您可以使代码更容易:

combina :: (Skyline, Skyline) -> Skyline
combina  (a,b) = ...

both :: (a -> b) -> (a,a) -> (b,b)
both f (x,y) = (f x, f y)

resuelveSkyline xs = combina (both resuelveSkyline (divide xs))

锻炼

  1. 您可以将任何功能从(a, b) -> c更改为a -> b -> c。编写一个完全符合的函数:

    fromPairFunc :: ((a,b) -> c) -> (a -> b -> c)
    fromPairFunc f = ...
    
  2. 你也可以这样做。写相应的函数:

    toPairFunc :: (a -> b -> c) -> ((a,b) -> c)
    toPairFunc f = ...
    
  3. 在原始代码中,请勿更改combina的类型,但要更正其定义并在正确的位置使用toPairFunc
  4. 在原始代码中,更改combina的类型,但不更改定义。而不是(resuelveSkyline(fst(divide(xs))),resuelveSkyline(snd(divide(xs)))),而是使用两个参数(resuelveSkyline(fst(divide(xs))))(resuelveSkyline(snd(divide(xs))))来调用它。您必须在正确的位置使用toPairFunc