2013-05-05 51 views
5

我想在Haskell中實現Ravi Sethi的小被子語言。塞西的小被子的概述可以在這裏看到:http://poj.org/problem?id=3201Ravi Sethi在Haskell的小被子語言

下面是我迄今爲止功能:

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 

我實現rotateturn功能使用,因爲它只是旋轉的名單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來解決,所以我相信我的代碼是相當混亂。)

回答

9

我們先來關注轉彎。對於一個原子[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 

據概述,在tu人們還需要旋轉符號'\' becoems '/',反之亦然,'-'變成'|',反之亦然。這可以通過在所有行上映射一個turnChar :: Char -> Char函數來實現。

+0

我在定義轉爲函數時遇到問題。如果我說'let turn = map reverse。轉置'並運行':t turn',它給了我'turn :: [[a]] - > [[a]]'。當我使用它作爲函數定義文件中的'turn'的類型簽名時,出現以下錯誤:'無法與實際類型a0 - > c0'匹配預期類型[[a]] – mrg1023 2013-05-05 23:58:39

+0

我無法診斷完全沒有看到代碼,但是這個消息看起來好像你正在傳遞一個函數來轉向。像「轉彎」或任何東西。你能否在某個地方發佈確切的問題部分? – 2013-05-06 00:03:00

+0

接受你的建議,'turn = map reverse。轉置「,它在解釋器中傳遞列表列表時工作。以下是我如何將它定義爲一個函數:'turn :: [[a]] - > [[a]] turn xs = map reverse xs。轉置xs'。這給了我以前的評論中顯示的類型錯誤。 – mrg1023 2013-05-06 00:14:02

2

下面是一個例子原子:

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

這裏是你如何顯示它:

AB 
CD 

這裏的問題是,自然的方式來旋轉(一維)列表(彈出一個元素關閉一端,將其推到其他)不旋轉的方式2x2平方。

我建議使用不同的數據結構來表示原子。例如您可以將一個原子表示爲列表清單:

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

甚至:'數據quilt a = Quilt {topLeft :: a,topRight :: a,bottomLeft :: a,bottomRight :: a}' – dflemstr 2013-05-05 21:51:59

+0

@dflemstr是的,但是這並不會推廣到他想要的時候將原子縫合在一起(儘管列表清單可能不會),而且我很累,沒有精力來解釋他爲什麼要這樣做(甚至在某處找到預先寫好的解釋)。 – dave4420 2013-05-05 21:57:35