【问题标题】:Haskell Functions and MappingHaskell 函数和映射
【发布时间】:2013-05-04 05:53:56
【问题描述】:

这是一项家庭作业,最后一点我真的很挣扎。我们正在用 Haskell 编写“Battleship”,除了一些关于函数式语言的一般性讲座之外,我们没有太多要讲的了。没有教科书等。我曾多次提到 LYAH,那里有好东西,但似乎没有针对这个特定问题的建议。

为了上下文,我将把我的整个战舰代码放在上面,这样你就可以看到我稍后引用的定义。

--A
data Row = A | B | C | D | E | F | G | H | I | J deriving (Enum, Ord, Show, Bounded, Eq, Read)
data Column = One | Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten  deriving (Enum, Ord, Show, Bounded, Eq, Read)
--B
data Address = Address Row Column deriving (Show, Read, Eq)
--C
data Cell = Cell Address Bool deriving (Show, Read, Eq)
--D
data Ship = Ship [Cell] deriving (Show, Eq)
--E
data Ships = Ships [Ship] deriving (Show, Eq)
--F
toAddress r c = Address (toEnum r) (toEnum c)
--G
toRowColumn (Address aRow aColumn) = (fromEnum aRow, fromEnum aColumn)
--H
allAddressesA = [ Address row column | row <- [A .. J], column <- [One .. Ten]]
--I
allAddressesB = [toAddress row column | row <- [0 .. 9], column <- [0 .. 9]]
--J
targetShip (Ship ship) (Address row column)
  | Address == map (\list -> (head Address Bool)) s
--K
targetShips [(Ships)] toAddress //TODO
--L
isSunk Ship ship
  |ship [] = true
  |otherwise foldl 
--M
areSunk [(Ships)] //TODO

现在我还将发布具体的作业描述,这样我需要帮助的内容就不会出现任何沟通错误:

(j) 编写一个函数 targetShip,它接受一个 Ship 和一个目标 地址作为它的两个参数。如果船有一个带有目标的单元格 地址,该单元格被标记为沉没。该船的更新版本是 回来。如果船是空的,则返回空船。 (1张地图, 116 个字符)

(k) 编写一个接受列表的函数 targetShips Ships 和目标地址作为其两个参数。它试图 击沉船列表中的每艘船。它返回更新船舶的列表。 如果没有船只,则返回空列表。 (1 地图,86 字符)

(l) 编写一个函数 isSunk 接受一个 Ship 作为它的 范围。如果船是空船,则返回真。否则, 如果所有单元格都标记为沉没,则返回 true。 (1折,78个字符)

(m) 编写一个函数 areSunk,它接受一个 Ships 列表作为它的 范围。如果没有船只,则返回 true。否则,返回 如果所有船只都被标记为沉没,则为真。 (1折,78个字符)

所以我在这里特别挣扎的是最后 4 个。我已经测试过的解决方案 (A - I),它们工作得很好。

首先,我们需要知道如何引用单元格值...地址和布尔值。

我们不能写更多的函数。

我假设您会想要对特定问题进行更多解释,因此我会密切关注。任何关于从哪里开始解决最后四个问题的提示将不胜感激。提前谢谢你...我现在会回到我的文本编辑器并尝试解决这个问题。

【问题讨论】:

  • 我猜点赞的同学也想知道这个问题的答案;)

标签: function haskell map


【解决方案1】:

(j) 编写一个函数 targetShip,它接受一个 Ship 和一个目标地址作为它的两个参数。如果船上有一个带有目标地址的单元格,则该单元格被标记为沉没。船的更新版本被退回。如果船是空的,则返回空船。 (1 幅地图,116 个字符)

函数targetShip,
参数Ship and a target address as its two parameters
产生Ship is returned

这些信息足以为您的函数写下类型注释。

targetShip :: Ship -> Address -> Ship
targetShip (Ship ship) (Address row column) 

If the ship is empty, the empty Ship is returned
而船是一个列表,或者一个列表要么是一个空列表[],要么是一个有尾的头,那么

targetShip :: Ship -> Address -> Ship
targetShip (Ship []) (Address row column) = Ship []
targetShip (Ship (x:xs)) (Address row column) = 

现在是最难的部分。
If the ship has a cell with the target address, that cell is marked sunk
一艘船是一个单元格列表,那么我需要为每个单元格(定义船舶)检查当前单元格的地址是否与函数参数提供的地址相同。
好的,让我们的模式匹配出现的头部x 来做吧。

targetShip :: Ship -> Address -> Ship
targetShip (Ship []) (Address row column)     = Ship []
targetShip (Ship (x:xs)) (Address row column) = 
    if x ... 

天哪,我做不到,因为不允许使用辅助功能,我需要更多信息。我需要将 x 的结构出现在我的模式匹配中,就像这样,

targetShip (Ship ((Cell address bool):xs)) (Address row column) = 

我的天啊,我不能再做更多了,好吧重做同样的事情,在我的模式匹配中更具表现力。

targetShip (Ship ((Cell (Address shipRow shipColumn) bool):xs)) (Address row column) = 

现在没关系,我可以做到。
我会让你完成它。

祝你好运

【讨论】:

  • 感谢您的赞赏。两个重要的指导,类型注解和模式匹配,真的很有帮助。
  • 非常感谢 :) 我们已经能够继续使用递归调用 targetShip 的 targetShips,我们现在正在巡航 :) 非常感谢。
【解决方案2】:

J:您必须退回一艘带有取决于地址的新列表的船。

targetShip (Ship oldCells) address = Ship newCells
  where newCells = ...
        f cell =

你如何找出新的细胞?该任务建议使用地图。所以你可以在oldCells 上映射一个函数ff 应该怎么做?如果它得到一个与 targetShip 的参数具有相同地址的单元格,它应该返回一个具有相同地址但具有沉没状态的新单元格。否则它应该只返回作为参数给出的单元格。

K:一旦你开始瞄准目标,应该很容易。按照建议使用map

L 和 J:非常相似。任务建议使用折叠。您以前尝试过使用折叠吗?有两种基本类型,foldrfoldl,它们都通过一个函数来工作,该函数接受两个参数,一个累加器和一个当前元素,并使用给定的累加器一次将一个元素折叠到累加器中。 .让我向您展示一些 foldl 的实际应用示例。

foldl (\acc x -> acc + x) 0 [1,2,3] -> 6 -- starting accumulator of 0
foldl (+) 0 [1,2,3] -> 6 -- same thing as above
foldl (&&) True [True, True, True] -> True -- folding booleans
foldl (&&) True [True, False, True] -> False -- more boolean folding
foldl (&&) True [] -> True -- folding an empty list yields the initial accumulator
foldl (\acc x -> acc && (x > 5)) True [6,7,8] -> True -- complex folding function.

希望您能看到最后一个函数,如何解决问题 L 和 J。否则请查看匿名函数中的模式匹配并查看 LYAH 中的 folding

【讨论】:

  • 嘿@Boris,非常感谢,这是一个很好的回应。根据您的回答,我了解折叠是如何进行的,但是,我看不到如何将它们应用于 L 和 J。同时,现在查看 LYAH,您是否有一个可能更适合这种情况的示例?
  • @Joodoo:你看到在最后一个例子中,每个列表元素是如何根据它是否满足某些标准(在本例中高于 5)被转换为布尔值的吗?实际的示例测试是否每个列表元素都满足该标准。这类似于 L 和 J 所需的。在 L 中,如果每个船单元都标记为沉没,则应该返回 true。为此,您的匿名函数应在其参数上使用模式匹配以轻松获得沉没状态。每艘船在任务 J 中应满足的标准是什么?
猜你喜欢
  • 2017-11-22
  • 1970-01-01
  • 1970-01-01
  • 2020-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多