Domanda

Vedi il mio precedente Domanda sulla composizione degli operatori OpenCV per una spiegazione di cosa sta succedendo.

Ho pensato una nuova interfaccia che consente di comporre le operazioni binarie distruttive in una sorta di modo composito:

newtype IOP a b = IOP (a -> IO b)

instance Category IOP where
    id = IOP return
    (IOP f) . (IOP g)  = IOP $ g >=> f

(&#&) :: IOP (Image c d) e -> IOP (Image c d) f 
             -> IOP (Image c d) (Image c d,Image c d)
(IOP f) &#& (IOP g) = IOP $ op
    where 
        op i = withClone i $ \cl -> (f i >> g cl >> return (i,cl))

runIOP (IOP f) img = withClone img f 
.

Con questo posso facilmente esprimere il "sottrae l'operatore gaussiano":

subtract  :: IOP (Image c d, Image c1 d1) (Image c d)
mulScalar :: d -> IOP (Image c d) (Image c d)
subtractScalar :: d -> IOP (Image c d) (Image c d)
gaussian  :: (Int, Int) -> IOP (Image GrayScale D32) (Image GrayScale D32)

(gaussian (11,11) &#& id) >>> subtract >>> mulScalar 5
.

Per me questo sembra un'alternativa abbastanza sicura, anche se non è ottimale nel senso, che probabilmente potrebbe riutilizzare anche l'immagine clonata se qualche operazione dopo sottracque richiederà questo. Ma sembra ancora un'alternativa accettabile alla versione completamente pura e non ottimizzata:

mulScalar 5 $ gaussian (11,11) img `subtract` img
-- Or with nicer names for the operators
5 * gaussian (11,11) img - img
.

Domande

    .
  1. è una struttura ragionevole in primo luogo?
  2. C'è una ragione per preferire la struttura nel precedente Domanda ?
  3. Come si estenderesti questo per implementare un'operazione 'Trova il valore minimo nell'immagine, sottrarlo dall'immagine e quindi moltiplicare l'immagine con la sua gamma (I.e Max-min).'
  4. dovrei dividerli in più domande?
È stato utile?

Soluzione

Continuando dal commento di Hammar, puoi solo usare la composizione di Kleisli per iniziare, evitando del tutto il IOP.Ho continuato a piangere come un sinonimo di tipo per la chiarezza.Inoltre, lo specialisco per restituire sempre un'unità e modifico alcune altre firme di tipo di conseguenza in modo da avere una differenza digitata tra le funzioni di mutazione (unità di restituzione) e le funzioni di manutenzione (restituendo un nuovo valore) e una funzione apOp che applica una funzione mutatoree restituisce il valore mutabile in modo che possiamo facilmente mettere in catena le mutazioni.

type ImageOp c d -> Image c d -> IO ()

(&#&) :: ImageOp c d -> ImageOp c d -> (Image c d) -> IO (Image c d, Image c d)
f &#& g = \i -> withClone i $ \cl -> f i >> g cl >> return (i,cl)

apOp :: ImageOp c d -> Image c d -> IO (Image c d)
apOp iop x = fmap x (iop x)

subtract  ::  Image c d ->  ImageOp c1 d1
mulScalar :: d -> ImageOp (Image c d)
subtractScalar :: d -> ImageOp (Image c d)
gaussian  :: (Int, Int) -> ImageOp GrayScale D32

myFun = (gaussian (11,11) &#& id) >=> (\(x,y) -> apOp (subtract x) y) >=> apOp (mulScalar 5) 

--pointfree
myFun = (gaussian (11,11) &#& id) >=> uncurry (apOp . subtract) >=> apOp (mulScalar 5) 
.

Modifica Se hai voglia, puoi scrivere &#& ordinatamente come segue:

f &#& g = uncurry (liftM2 (,)) . (apOp f &&& withClone (apOp g))
.

Che, penso, è un buon argomento per questo stile essere piuttosto espressivo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top