6

我正在尝试在 Haskell 中实现 Ravi Sethi 的 Little Quilt 语言。Sethi的小被子的概述可以在这里看到:http ://poj.org/problem?id=3201

以下是我目前拥有的功能:

import Data.List.Split

rotate :: Int -> [a] -> [a]
rotate n xs = iterate rot xs !! n 
    where 
        rot xs = last xs : init xs 

turn :: [a] -> [a]
turn x = rotate 2 x

grid :: Int -> [String] -> String
grid n = unlines . map concat . chunksOf n

printAtom :: [String] -> IO() 
printAtom x = putStrLn $ grid 2 x  

我实现rotate了在我的函数中使用,因为它只是将列表时间向左turn旋转。n

这是一个示例原子:

let a0 = ["#", "@", "#", "#"]

为了说明如何查看原子,我将使用 printAtom 函数:

printAtom a0 

#@
## 

当我调用turnatoma0并打印生成的 atom 时,我会得到以下结果(turn应该代表整个 atom 顺时针旋转 90 度):

##
#@

这是第一回合的预期输出。这将对应于定向原子a1。打开原子a1应该产生:

@#
## 

然而,给定turn函数的约束,它只是简单地将原子返回到a0状态。为了解决这个问题,我尝试实现一个函数 ,newTurn它使用基于测试 using 的守卫chunksOf 2 atom,如下所示:

newTurn :: [a] -> [a]
newTurn x
| chunksOf 2 x == [["#", "@"], ["#", "#"]] = rotate 2 x
| chunksOf 2 x == [["#", "#"], ["#", "@"]] = rotate 1 x 
| chunksOf 2 x == [["@", "#"], ["#", "#"]] = rotate 2 x 
| chunksOf 2 x == [["#", "#"], ["@", "#"]] = rotate 1 x 

我几乎可以肯定我不了解如何使用守卫,而且我绝对知道我不太了解函数定义上的类型约束。当我尝试将该newTurn函数导入 ghci 时,出现此错误:

functions.hs:19:29:
Couldn't match type `a' with `[Char]'
  `a' is a rigid type variable bound by
      the type signature for newTurn :: [a] -> [a] at functions.hs:18:1
In the expression: "#"
In the expression: ["#", "@"]
In the second argument of `(==)', namely `[["#", "@"], ["#", "#"]]'

在对我的问题进行了冗长的解释之后,基本上我需要知道的是如何更改我的turn函数以表示原子实际顺时针旋转 90 度?(注意:这是我尝试在 Haskell 中处理的第一个项目,所以我确信我的代码非常混乱。)

4

2 回答 2

10

让我们首先关注转弯。对于一个原子[a, b, c, d],调用grid 2它来打印产量

a b
c d

顺时针旋转 90° 将导致

c a
d b

来自列表[c, a, d, b]。所以顺时针转动不是列表元素的循环交换。如果只需要考虑 2×2 个原子,则turn使用平面列表的自然实现将是

turn [a,b,c,d] = [c,a,d,b]
turn _         = error "Not an atom"

但是,根据概述,事情并没有那么简单,您可以缝制被子,因此您可以得到任何尺寸的被子,m×n只要mn都是均匀的。因此,对被子使用平面列表表示并不是最好的主意。

假设您将被子表示为列表列表,每行一个列表,例如

[ [a,b,c,d]
, [e,f,g,h] ]

被子2×4。顺时针旋转 90° 得到4×2被子

[ [e,a]
, [f,b]
, [g,c]
, [h,d] ]

现在,标准库中没有任何东西可以直接执行此操作,但是在 中Data.List,我们有transpose,它将2×4上面的被子转换为

[ [a,e]
, [b,f]
, [c,g]
, [d,h] ]

然后我们就到了一半:

turn = map reverse . transpose

根据概述,在转动时,还需要旋转符号,'\'becoems'/'反之亦然,becoming反之亦然。这可以通过在所有行上映射一个函数来实现。'-''|'turnChar :: Char -> Char

于 2013-05-05T21:57:39.040 回答
2

这是一个示例原子:

["A", "B", "C", "D"]

以下是您的显示方式:

AB
CD

这里的问题是旋转(一维)列表(从一端弹出一个元素并将其推到另一端)的自然方法不是旋转 2x2 正方形的方法。

我建议使用不同的数据结构来表示原子。例如,您可以将原子表示为列表列表:

[["A", "B"], ["C", "D"]]
于 2013-05-05T21:46:34.747 回答