سؤال

أريد إنشاء موناد الخاص بي. هذا ما كتبته:

data LeafConType a = LeafCon (a,Int,Int)

instance Monad (LeafConType ) where
return = LeafCon 
lc@(LeafCon (t,i,n)) >>= f = if i>=n
                                then lc
                                else f (t,i,n)

لكن هذا لا يعمل. يقول GHC:

leafcon.hs:26:1:
    Occurs check: cannot construct the infinite type: a = (a, Int, Int)
    When generalising the type(s) for `return'
    In the instance declaration for `Monad LeafConType'

leafcon.hs:27:1:
    Occurs check: cannot construct the infinite type: a = (a, Int, Int)
    When generalising the type(s) for `>>='
    In the instance declaration for `Monad LeafConType'

ما الخطأ فى ذلك؟


أريد إجراء حسابات بينما أنا أقل من n. يجب أن تكون ثوابت من قبل لا أعرف بعد كيفية القيام بذلك بشكل صحيح. يجب أن يكون مزيج من الدولة وربما. إذا كان لديك بعض النصائح ، فلا تتردد في مشاركتها معي: P

هل كانت مفيدة؟

المحلول

عن return:

Prelude> :t return
return :: (Monad m) => a -> m a 

لذا return يأخذ حجة من النوع a, ويعيد شيء من النوع m a. في هذه الحالة m هو LeafConType, ، لذا LeafConType a يتم إرجاع.

لنفترض الآن أننا نمر True. ثم a = Bool, ، لذلك يجب أن يكون نوع العودة LeafConType Bool. ومع ذلك ، يمكنك تحديد:

return = LeafCon

لذا، return True يصبح LeafCon True. لكن هذا غير مسموح به ، لأن تعريف نوع LeafConType ينص علي

data LeafConType a = LeafCon (a, Int, Int)

وذلك ل LeafConType Bool الحجة ل LeafCon يجب أن يكون النوع (Bool, Int, Int), ، ليس مجرد Bool. وهذا ما يعنيه خطأ التجميع: a لا يمكن أن يكون هو نفسه (a, Int, Int). ذكرت:

أريد أن أقوم بحسابات أثناء i أقل من n.

هذا يعني أنك ستحتاج إلى بعض القيم الافتراضية لـ i و n, ، وإلا سيكون من المستحيل تحديد return. إذا كان كلاهما صفرًا بشكل افتراضي ، فيمكنك تحديد:

return a = LeafCon (a, 0, 0)

عن (>>=):

Prelude> :t (>>=)
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b

انظر الآن إلى تطبيقك (تدوين مختلف قليلاً ، نفس الفكرة):

lc@(LeafCon (t, i, n)) >>= f | i >= n    = lc 
                             | otherwise = f t

ما نراه هنا ، هل هذا lc يتم إرجاعه عندما i >= n. لكن lc من النوع LeafConType a, ، في حين f هي وظيفة قد ترجع قيمة النوع LeafConType b, ، ل أي b. نتيجة لذلك يمكن أن يكون ذلك b لا يساوي a وبالتالي هذه الأنواع لا تتطابق. في الختام ، عليك بجدية أن تطرح نفسك على سؤال واحد:

  هل يمكن التعبير عن هذا النوع من الحساب كموناد على أي حال؟

نصائح أخرى

الوظائف التي حددتها >>= و return لا ترضي الأنواع المطلوبة بواسطة Monad:

return :: a -> LeafConType a

بالنظر إلى الإعلان

return = LeafCon

أنت تعطي الوظيفة النوع غير المتوافق

return :: (a, Int, Int) -> LeafConType a

بيان مثل return 42 لذلك سيكون مستحيلًا في مونادك.

لا أفهم ما يجب أن تفعله موناد على الإطلاق. أولا إلقاء نظرة على موناد البسيطة والعمل!

instance Monad [] where
    (>>=) = concatMap
    return a = [a]

instance Monad Maybe where
    return = Just
    (Just x) >>= f = f x
    Nothing >>= f = Nothing

انطلاقًا من وصفك لما تريد أن تفعله موناد ، أعتقد أنك تريد شيئًا مثل هذا:

data LeafConType a = LeafCon { runLeafCon' :: Int -> Int -> (Maybe a, Int, Int) }

runLeafCon :: Int -> Int -> LeafConType a -> Maybe a
runLeafCon i n lc = let (t, _, _) = runLeafCon' lc i n in t

getI :: LeafConType Int
getI = LeafCon $ \i n -> (Just i, i, n)

getN :: LeafConType Int
getN = LeafCon $ \i n -> (Just n, i, n)

setI :: Int -> LeafConType ()
setI i = LeafCon $ \_ n -> (Just (), i, n)

setN :: Int -> LeafConType ()
setN n = LeafCon $ \i _ -> (Just (), i, n)

instance Monad LeafConType where
    return t = LeafCon $ \i n -> if (i < n) 
                                 then (Just t, i, n) 
                                 else (Nothing, i, n)

    (LeafCon k) >>= f = 
        LeafCon $ \i n -> 
            let (t, i', n') = k i n
            in case t of
                 Nothing -> (Nothing, i', n')
                 (Just t') -> if (i' < n')
                              then runLeafCon' (f t') i' n'
                              else (Nothing, i, n)


example :: Int -> LeafConType ((), Int)
example x = do 
  i <- getI
  m <- setI (i + x)
  return (m, i + x)

بعض الأمثلة:

*Main> runLeafCon 2 10 $ example 4
Just ((),6)
*Main> runLeafCon 2 10 $ example 8
Nothing
*Main> runLeafCon 2 10 $ example 7
Just ((),9)

لقد ألقيت هذا معًا بسرعة كبيرة ، إنه قبيح إلى حد ما ، ولم أتحقق من معرفة ما إذا كان يطيع أي من قوانين Monad ، لذا استخدم على خطرك! قون

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