我正在尝试在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
#@
##
当我在原子turn
上调用a0
并打印生成的原子时,我最终得到以下结果(turn
应该代表顺时针旋转90度到整个原子):
##
#@
这是第一回合的预期输出。这将对应于定向原子a1
。启用原子a1
应该产生:
@#
##
但是,考虑到turn
函数的约束,它只是将原子返回到a0
状态。为了解决这个问题,我试图实现一个函数newTurn
,它使用基于使用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中尝试解决的第一个项目,所以我确定我的代码非常混乱。)
答案 0 :(得分: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
和m
都是偶数的任何维n
的被子。因此,使用平面列表表示被子不是最好的主意。
假设您将被子表示为列表列表,每行一个列表,例如
[ [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 '/'
,反之亦然,'-'
变为'|'
,反之亦然。这可以通过在所有行上映射turnChar :: Char -> Char
函数来实现。
答案 1 :(得分:2)
这是一个示例原子:
["A", "B", "C", "D"]
以下是您展示它的方式:
AB
CD
这里的问题是旋转(一维)列表(从一端弹出元素并将其推到另一端)的自然方式不是旋转2x2方格的方法。
我建议使用不同的数据结构来表示原子。例如你可以将一个原子表示为一个列表列表:
[["A", "B"], ["C", "D"]]