2012-02-05 11 views
5

l'altro giorno ho scritto un piccolo programma per raccogliere un gruppo di numeri in una matrice - data Matrix = Matrix [[Int]] a partire da un angolo - Corner e seguire un percorso - [Direction] tutti dei tre tipi sono esempio di una classe Transformablein haskell - utilizzo di più versioni di una funzione senza dargli nomi diversi

allora ho una funzione che genera una funzione di trasformazione, che trasforma un dato angolo e la direzione - a LeftUp e Right

turnLUR :: Transformable a => (Corner, Direction) -> a -> a 

quindi uso questa funzione a "messe" tutti i numeri nella matrice:

harvest :: Matrix → [(Corner,Direction)] → [Int] 
harvest _ [] = [] 
harvest (Matrix []) _ = [] 
harvest as (cd:csds) = b ++ harvest (Matrix bs) csds' --cd = (Corner,Direction) 
        where f1 = turnLUR cd -- Matrix -> Matrix 
          f2 = turnLUR cd -- Corner -> Corner 
          f3 = turnLUR cd -- Direction -> Direction 
          Matrix (b:bs) = f1 as -- b = first line of [[Int]] 
          fcfd (c,d) = (f2 c,f3 d) 
          csds' = map fcfd csds 

Ora la mia domanda perché devo mettere per iscritto f1, f2 e f3 invece di utilizzare una funzione f tre volte (! mantenere DRY nella mia mente) - tutti e tre i tipi Corners, Directions e Matrix sono istanze di class Transformable.

Come scrivere il codice senza: eseguire tre versioni della "stessa" funzione?

risposta

11

Questo a causa dello monomorphism restriction. Dategli una firma di tipo esplicito, e sarete in grado di riutilizzare la stessa funzione ogni volta:

harvest :: Matrix → [(Corner,Direction)] → [Int] 
harvest _ [] = [] 
harvest (Matrix []) _ = [] 
harvest as (cd:csds) = b ++ harvest (Matrix bs) csds' --cd = (Corner,Direction) 
        where f :: Transformable a => a -> a 
          f = turnLUR cd 
          Matrix (b:bs) = f as -- b = first line of [[Int]] 
          fcfd (c,d) = (f c,f d) 
          csds' = map fcfd csds 

In alternativa, è possibile disattivarlo mettendo {-# LANGUAGE NoMonomorphismRestriction #-} nella parte superiore del file.

La restrizione monomorfismo non è ben voluto - manuale, anche di GHC si riferisce ad esso come il dreaded monomorphism restriction - ma ci sono alcuni casi angolo difficile, soprattutto legati alla condivisione (vedere la pagina wiki ho linkato per maggiori informazioni), che evita. In questo caso, ti consiglio di aggiungere solo la firma del tipo.

+3

Si noti che la limitazione del monomorfismo riguarda solo le funzioni scritte in stile inutile (così come i valori che non sono funzioni), quindi se si definisce 'f' utilizzando parametri espliciti, non sarà influenzato dalla restrizione anche se si non dargli una firma tipo – sepp2k

+0

quindi è il tipo signature 'f :: Transformable a => a -> a' mantenendo la funzione specificata in una signature di tipo; e senza di esso il compilatore deduce che 'f' sia di tipo' Matrix -> Matrix' dato che è il suo primo utilizzo. Grazie mille per aver chiarito questo. Soprattutto non sapevo che la firma potesse risolvere questa limitazione del monomorfismo. – epsilonhalbe

Problemi correlati