Haskell将点列表转换为字符串

4

我正在完成一项任务,需要一些帮助。这是最后一部分,但我真的很苦恼,不知道该如何着手。以下是问题:

Add a function render which takes an image and returns a string that, if printed, would give the diagrammatic representation of the image as illustrated below (making sure to include the one point border around all sides of the image). As an example, render t should return

".|...\n.xxx.\n-+x--\n.|...\n"

(where the points in the image are denoted 'x', the origin is denoted '+', and the horizontal and vertical axes are denoted '-' and '|' respectively):

.|...
.xxx.
-+x--
.|...

(String we produce by render t function can be printed by doing putStr (render t) to achieve above result).

image and t is just this:

type Point = (Int,Int)
type Image = [Point]
t :: Image
t=[(0,1),(1,0),(1,1),(2,1)]

首先,我需要另一个函数来完成一些无法在渲染中完成的任务。我知道要查看y和x的最大/最小值以获取边界,并且我有一个函数可以做到这一点。我还有一个函数,可以在每n个字符后将换行符插入字符串中。


1
Haskell 可能需要一些时间来理解,特别是当你刚开始学习时。为了澄清,你需要一个将 t=[(0,1),(1,0),(1,1),(2,1)] 转换为 ".|...\n.xxx.\n-+x--\n.|...\n" 的函数。 - Paperwaste
还有没有关于图像大小的限制,或者我们的函数需要自己确定? - Paperwaste
我的意思更像是点的位置。如果其中一个点是(1,1000),我们的图像会变得非常大。 - Paperwaste
这是我所知道的最好的Haskell资源,我现在正在工作,但我会尽快回复您一个适当的答案。http://learnyouahaskell.com/ - Paperwaste
2
删除问题并不是有益的,即使您对问题感到不满意。请把它放回来。 - Neil Forrester
显示剩余3条评论
2个回答

6

所以你有一个获取尺寸的函数:

dimensions :: Image -> (Point, Point)

需要返回左上角和右下角的点。然后按排序顺序获取这些点:

sortImage :: Image -> Image

按最大的y和最小的x排序的列表(提示:Data.List.sortBy是您的朋友)。实际上这并不是必需的,但它可以使以后的工作更加容易。然后,您可以创建一张空白图像(即只有轴和'.',或者您可以使用空格获得更清晰的外观)。

blankImage :: (Point, Point) -> [String]

超出你的尺寸范围。确保返回一行行的列表,稍后可以使用换行符连接,但现在让它更易于处理。现在,[String] = [[Char]],所以你有一个二维字符数组。你有一个Point坐标列表,但是你需要将它们移动,使得左上角坐标现在是(0, 0)。这样我们就可以在数组上使用普通的索引来设置点。幸运的是,我们已经在dimensions中计算出了偏移值。

然后你需要一个函数,该函数接受blankImage的输出并使用你现在偏移的Image中的值替换字符。由于Point现在是blankImage中的索引,因此这应该很容易实现。

fillImage :: Image -> [String] -> [String]

所以,该过程如下:
import Data.List

showImage :: Image -> String
showImage img = intercalate "\n" filled
    where
        sortedImg = sorteImage img
        (upperL, lowerR) = dimensions sortedImg
        blank = blankImage (upperL, lowerR)
        offsetImg = offsetImage upperL sortedImg
        filled = fillImage offsetImg blank
    putStrLn $ intercalate "\n" filled

函数intercalate可以将你的[String]用换行符连接起来,变成一个大字符串。
从你的评论中我看出你刚接触Haskell,所以我想说如果你需要更多帮助,我会给一些提示,但最好是先自己尝试解决问题。如果你遇到困难,请发表评论,我会编辑我的回答来帮助你跨过障碍。

1
你应该使用unlines而不是intercalate "\n",因为示例在最后一行之后也有一个换行符。 - raymonad
这取决于使用情况。我个人更喜欢 intercalate,因为它的作用类似于 Python 中的 string.join,而 Python 是我的主要语言。如果有人想要改成 "\r\n",那么这很容易解决。但实际上它们是基本等效的方法,差异微不足道。 - bheklilr

0

以下是一些需要考虑的事项:

  • 从功能上讲,图像是什么?暂时忽略边界,图像是从坐标到显示在该坐标上的任何内容的函数。尝试为图像想出一个类型签名。如果使用type将其称为FImage,则可以获得奖励分数。将这些函数视为您的主要对象(请记住,函数是一等公民)。
  • 将轴实现为FImage。请注意,您不需要任何边界。这不是很好吗?
  • 实现一个函数,该函数接受FImagePoint,并生成具有正确位置的xFImage
  • 从点列表中找出边界。像往常一样,首先要考虑的是:这个的类型签名是什么?
  • 给定FImage和边界,生成最终的String。您可能想在此处使用列表理解。
  • 把它们全部放在一起。这里隐藏了一个折叠!其中一个参数将是点列表。其他参数是什么(基本情况和组合函数)。在Haskell专业知识的这个水平上,不要太担心它是foldl还是foldr,两者都可以(如果类型匹配)。
  • 完成了:-)

祝学习愉快!

(这之前是对于此问题的重复问题的答案。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接