2009-12-20 18 views
10

Recentemente mi sono imbattuto in questo problema e ho trovato una soluzione, ma mi chiedo se ci siano soluzioni migliori (o solo più idiomatiche).Come "decomprimere" una struttura in haskell

Ho una struttura per un colore:

data Rgb = Rgb Double Double Double 

e non v'è una funzione che vorrei passare i componenti di colore a individualmente, in realtà dal Cairo:

setSourceRGB :: Double -> Double -> Double -> Render() 

Quindi ho bisogno per "decomprimere" questa struttura dati in qualche modo, dal momento che setSourceRGB non accetta uno Rgb. Ho trovato due modi. Uno è quello di definire una funzione di applicare il contenuto di un Rgb:

applyRgb :: (Double -> Double -> Double -> t) -> Rgb -> t 
applyRgb f (Rgb r g b) = f r g b 

Allora posso fare:

applyRgb setSourceRGB rgb 

Un altro modo mi è venuto in mente è di fare un'espressione in linea lambda con un caso, il che significa che non c'è bisogno di definire una funzione separata:

(\z -> (case z of (Rgb r g b) -> setSourceRGB r g b)) rgb 

io non sono del tutto soddisfatto di questo però, in qualche modo l'applicazione di una funzione solo per passare alcuni valori non mi sembra giusto. Mi piacerebbe essere in grado di capovolgerlo e "convertire" il Rgb nel tipo giusto per setSourceRGB. Purtroppo mi sembra che è tutto impossibile avere una funzione

fromRgb :: Rgb -> Double -> Double -> Double 

che può essere passato a setSourceRGB. Forse applyRgb è la soluzione migliore, ma mi chiedo se c'è un modo migliore che vi permetterà di esprimere come:

setSourceRGB (fromRgb rgb) 
+3

Che cos'è il "caso .. di'? '(\ (Rgb r g b) -> SetSource r g b) rgb' – ephemient

risposta

3

No, non si può scrivere qualcosa di simile setSourceRGB (fromRgb RGB), perché sarà basta dare un argomento alla funzione, quindi applyRgb sembra la soluzione migliore. Se vi piace questo genere di cose, è anche possibile utilizzare applyRgb come una funzione infisso:

setSource `applyRgb` rgb 

Se si utilizza spesso questa funzione, il tuo grado rendere il codice più facile da leggere attraverso la definizione di un nome per applyRgb setSource.

4

BTW, si dovrebbe quasi certamente avere:

data Rgb = Rgb !Double !Double !Double 

invece, e compilare con -funbox-strict-campi, in modo che i componenti possono essere estratti in valori doppi primitivi privi di allocazione.

2

Non è possibile "decomprimere" nulla in più argomenti senza avvolgere la funzione stessa nei modi che hai capito.

Tuttavia, per coerenza, probabilmente chiamerei l'helper qualcosa del genere.

-- from Prelude... 
uncurry :: (a -> b -> c) -> (a, b) -> c 
uncurry f (a, b) = f a b 

-- yours? 
uncurryRgb :: (Double -> Double -> Double -> a) -> Rgb -> a 
uncurryRgb f (Rgb r g b) = f r g b 
+0

È necessario correggere la definizione in modo che corrisponda alla firma. In questo momento i casi sono diversi. – Martijn

+0

Augh, typo. Bene, a parte le differenze di ortografia, questa è la stessa definizione di OP 'applyRgb' ... – ephemient