2013-05-05 11 views
5

Sto cercando di implementare la lingua di Little Quilt di Ravi Sethi in Haskell. Una panoramica della piccola trapunta di Sethi può essere visto qui: http://poj.org/problem?id=3201Ravi Sethi's Little Quilt Language in Haskell

Qui ci sono le funzioni che ho finora:

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 

ho implementato rotate da utilizzare nella mia funzione turn, mentre ruota semplicemente un elenco n volte a sinistra.

Ecco un esempio atomo:

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

Per illustrare come gli atomi sono visti, userò la funzione printAtom:

printAtom a0 

#@ 
## 

Quando chiamo turn su atomo a0, e stampare il risultante atomo, finisco con il seguente (turn dovrebbe rappresentare una svolta in senso orario di 90 gradi per l'intero atomo):

che è l'uscita prevista per il primo turno. Questo corrisponderebbe all'atomo orientato a1. Una svolta su atomo a1 dovrebbe produrre:

@# 
## 

Tuttavia, dati i vincoli della funzione turn, restituisce semplicemente l'atomo allo stato a0. Per combattere questo, ho cercato di implementare una funzione, newTurn, che utilizza guardie sulla base di un test utilizzando chunksOf 2 atom, mostrato qui:

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 

Sono quasi positivo non sto capire come utilizzare le guardie, e mi Sicuramente so che non capisco perfettamente i vincoli di tipo posti sulla definizione di una funzione. Quando provo ad importare la funzione newTurn in ghci, sto ottenendo questo errore:

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 `[["#", "@"], ["#", "#"]]' 

Dopo questa spiegazione prolisso del mio problema, in sostanza quello che ho bisogno di sapere è come ho potuto cambiare la mia funzione di turn rappresenta un vero giro di 90 gradi in senso orario di un atomo? (Nota: questo è il primo progetto che ho cercato di affrontare in Haskell, quindi sono sicuro che il mio codice è piuttosto disordinato.)

risposta

9

Let al turn.Per un atomo [a, b, c, d], chiamando grid 2 su di esso per i rendimenti stampa

a b 
c d 

Girando che il 90 ° in senso orario si tradurrebbe in

c a 
d b 

che proviene dalla lista [c, a, d, b]. Quindi una svolta in senso orario non è uno scambio ciclico di elementi di lista. Se dovrebbero essere considerati solo 2 × 2 atomi, l'attuazione naturale turn utilizzando una semplice lista sarebbe

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

Ma, secondo i dettagli, le cose non sono così semplici, si può cucire trapunte, in modo da può ottenere trapunte di qualsiasi dimensione m×n dove sia m sia n sono pari. Quindi usare una rappresentazione di lista piatta per le trapunte non è l'idea migliore.

Supponiamo che si rappresentato trapunte come una lista di liste, ogni riga una lista, così per esempio

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

per un 2×4 trapunta. Rotazione che il 90 ° in senso orario si ottiene la 4×2 trapunta

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

Ora, non c'è niente nelle librerie standard che lo fa direttamente, ma, in Data.List, abbiamo transpose, che trasforma il 2×4 trapunta sopra in

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

e siamo quindi a metà strada:

turn = map reverse . transpose 

Secondo i dettagli, quando tu Inoltre, è necessario ruotare i simboli, '\' perché '/' e viceversa, '-' diventa '|' e viceversa. Ciò si otterrebbe mappando una funzione turnChar :: Char -> Char su tutte le righe.

+0

Non riesco a definire la svolta come una funzione. Se dico 'lascia girare = mappa indietro. trasporre' ed eseguire ': t turn' mi dà' turn :: [[a]] -> [[a]] '. Quando lo uso come firma del tipo di 'turn' in un file di definizione di funzione, ottengo il seguente errore:' Impossibile trovare il tipo previsto [[a]] con il tipo effettivo a0 -> c0' – mrg1023

+0

Non riesco a diagnosticare esattamente senza vedere il codice, ma quel messaggio sembra come se da qualche parte si passasse una funzione a 'turn'. Qualcosa come "turn turn" o qualsiasi altra cosa. Puoi postare la parte problematica esatta da qualche parte? –

+0

Seguendo il tuo suggerimento, 'turn = map reverse. transpose', che funziona quando viene passato un elenco di liste nell'interprete. Ecco come ho provato a definirlo come una funzione: 'turn :: [[a]] -> [[a]] turn xs = map reverse xs. trasporre xs'. Questo mi dà l'errore di tipo, come mostrato nel mio commento precedente. – mrg1023

2

Ecco un esempio atomo:

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

Ed ecco come lo mostriamo:

AB 
CD 

il problema qui è che il modo naturale di ruotare un (unidimensionale) lista (pop un elemento fuori un'estremità e spingerlo sull'altro) non è il modo per ruotare una 2x2 quadrati.

Si consiglia di utilizzare una struttura dati diversa per rappresentare un atomo. per esempio. si potrebbe rappresentare un atomo come una lista di liste: primo fuoco

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

O anche: 'data Quilt a = Quilt {topLeft :: a, topRight :: a, bottomLeft :: a, bottomRight :: a}' – dflemstr

+0

@dflemstr Vero, ma questo non si generalizza a quando vuole cuciamo insieme gli atomi (anche se probabilmente gli elenchi di elenchi non lo faranno), e sono stanco e non ho l'energia per spiegare perché vuole farlo in quel modo (o anche trovare una spiegazione pre-scritta da qualche parte). – dave4420