واجهة أفضل لتكوين العوامل المدمرة، الجزء الثاني

StackOverflow https://stackoverflow.com/questions/6069015

  •  07-09-2020
  •  | 
  •  

سؤال

انظر بلدي في وقت سابق سؤال حول تأليف مشغلي opencv لشرح ما يجري.

لقد فكرت في واجهة جديدة تسمح بتأليف عمليات ثنائية مدمرة بطريقة قابلة للتركيب:

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 

بهذا يمكنني بسهولة التعبير عن "طرح العامل الغوسي":

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

بالنسبة لي، يبدو هذا بديلاً آمنًا تمامًا، على الرغم من أنه ليس الأمثل بمعنى أنه ربما يمكنه إعادة استخدام الصورة المستنسخة أيضًا إذا كانت بعض العمليات بعد الطرح تتطلب ذلك.لكنه لا يزال يبدو بديلاً مقبولاً للنسخة النقية وغير المحسنة تمامًا:

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

أسئلة

  1. هل هذا هيكل معقول في المقام الأول؟
  2. هل هناك سبب لتفضيل الهيكل في السابق سؤال?
  3. كيف يمكنك توسيع هذا لتنفيذ عملية "العثور على الحد الأدنى للقيمة في الصورة، وطرحها من الصورة ثم ضرب الصورة بنطاقها (أي الحد الأقصى للدقيقة)."
  4. هل يجب علي تقسيم هذه الأسئلة إلى أسئلة متعددة بدلاً من ذلك؟
هل كانت مفيدة؟

المحلول

استمرارًا لتعليق هامر، يمكنك فقط استخدام تركيبة kleisli لتبدأ، وتجنب IOP تمامًا.لقد احتفظت بـ ImageOp كمرادف للنوع من أجل الوضوح.أيضًا، قمت بتخصيصها لإرجاع الوحدة دائمًا، وغيرت بعض توقيعات النوع الأخرى وفقًا لذلك بحيث يكون لدينا فرق مكتوب بين وظائف التحوير (إرجاع الوحدة) ووظائف الاستنساخ (إرجاع قيمة جديدة)، والوظيفة apOp الذي يطبق وظيفة الطفرة ويعيد القيمة المتحولة حتى نتمكن من ربط الطفرات بسهولة.

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) 

يحررإذا كنت تشعر بذلك، يمكنك الكتابة &#& بدقة على النحو التالي:

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

والتي أعتقد أنها حجة جيدة لكون هذا الأسلوب معبرًا جدًا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top