Haskell的Ravi Sethi小被子语言

时间:2013-05-05 20:38:33

标签: haskell list-manipulation

我正在尝试在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中尝试解决的第一个项目,所以我确定我的代码非常混乱。)

2 个答案:

答案 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×nm都是偶数的任何维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"]]