Question

Voir mon précédent question sur la composition des opencv opérateurs pour une explication de ce qui se passe.

J'ai pensé à une nouvelle interface qui permet de composer des destructeurs d'opérations binaires dans une sorte de composable façon:

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 

Avec cela, je peux facilement exprimer la " soustraction de la gaussienne de l'opérateur:

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

Pour moi, cela semble une assez alternative sûre, même si elle n'est pas optimale dans le sens, qu'il n'aurait probablement ré-utiliser également l'image clonée si une opération après soustraire cette.Mais il semble toujours comme une solution de rechange acceptable à la pure et unoptimized version:

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

Questions

  1. Est-ce une structure raisonnable, en premier lieu?
  2. Est-il une raison pour préférer la structure dans le précédent question?
  3. Comment voulez-vous étendre cette mesure à mettre en œuvre une opération de " trouver la valeur minimale de l'image, de la soustraire de l'image, puis de multiplier l'image avec sa gamme (j'.e max-min).'
  4. Dois-je les scinder en plusieurs questions à la place?
Était-ce utile?

La solution

Continuant à partir de hammar commentaire, vous pouvez simplement utiliser kleisli composition pour commencer, en évitant le IOP tout à fait.J'ai gardé ImageOp comme un type synonyme pour plus de clarté.Aussi, je me suis spécialisé à toujours retourner l'appareil, et changé quelques autres type de signatures en conséquence, de sorte que nous avons tapé la différence entre une mutation des fonctions (de retour de l'unité) et cloining fonctions (de retour d'une nouvelle valeur), et une fonction apOp qui s'applique à une mutation de la fonction et renvoie la muté valeur, de sorte que nous pouvons chaîne mutations facilement.

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) 

Modifier Si vous en avez envie, vous pouvez écrire &#& parfaitement comme suit:

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

Ce qui, je pense, est un bon argument en faveur de ce style étant assez expressif.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top