Pregunta

vea mi anterior Pregunta sobre la composición de operadores de OPENCV para una explicación de lo que esta pasando

Pensé una nueva interfaz que permite componer operaciones binarias destructivas en un tipo de forma composable:

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 esto puedo expresar fácilmente el 'restar el operador 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

Para mí, esto parece una alternativa bastante segura, aunque no es óptimo en el sentido, que probablemente pueda reutilizar también la imagen clonada si alguna operación después de restar exigiría esto. Pero todavía parece una alternativa aceptable a la versión completamente pura y no partimizada:

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

Preguntas

  1. es esta una estructura razonable en primer lugar?
  2. ¿Hay alguna razón para preferir la estructura en el anterior Pregunta ?
  3. ¿Cómo se extendería esto a implementar una operación "encontrar el valor mínimo en la imagen, restánlo de la imagen y luego multiplique la imagen con su rango (es decir, MAX-MIN) '
  4. ¿Debo dividir estos en varias preguntas en su lugar?
¿Fue útil?

Solución

Continuando desde el comentario de Hammar, solo puede usar la composición de Kleisli para comenzar, evitando el IOP por completo.He seguido ImagOP como un sinónimo de tipo de claridad.Además, lo especializé en la unidad de retorno siempre, y cambié algunas otras firmas de tipo en consecuencia, de modo que tenemos una diferencia escrita entre las funciones de mutación (unidad que devuelve) y las funciones de Conego (devolviendo un nuevo valor) y una función apOp que aplica una función de mutación.y devuelve el valor mutado para que podamos cadenar mutaciones fácilmente.

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) 

editar Si se siente así, puede escribir &#& cuidadosamente de la siguiente manera:

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

que, creo, es un buen argumento para que este estilo sea bastante expresivo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top