我正在为大学学习哈斯克尔,我正试图做一个天际线问题 - > 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个天际线并返回一个与之合并的新天际线。
答案 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))
您可以将任何功能从(a, b) -> c
更改为a -> b -> c
。编写一个完全符合的函数:
fromPairFunc :: ((a,b) -> c) -> (a -> b -> c)
fromPairFunc f = ...
你也可以这样做。写相应的函数:
toPairFunc :: (a -> b -> c) -> ((a,b) -> c)
toPairFunc f = ...
combina
的类型,但要更正其定义并在正确的位置使用toPairFunc
。combina
的类型,但不更改定义。而不是(resuelveSkyline(fst(divide(xs))),resuelveSkyline(snd(divide(xs))))
,而是使用两个参数(resuelveSkyline(fst(divide(xs))))
和(resuelveSkyline(snd(divide(xs))))
来调用它。您必须在正确的位置使用toPairFunc
。