Domanda

Voglio creare la mia monade. Questo è ciò che ho scritto:

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)

Ma questo lavoro Dont. GHC dice:

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'

Cosa c'è di sbagliato in questo?


che voglio fare calcoli, mentre i è inferiore a n. n dovrebbe essere costanti per non so ancora come fare questo corretto. Dovrebbe essere un po 'di mix di Stato e di darsi. Se si dispone di alcuni consigli non esitate a condividere con me: P

È stato utile?

Soluzione

Informazioni su return:

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

Quindi return prende un argomento di tipo a, e restituisce qualcosa di tipo m a. In questo caso è m LeafConType, così LeafConType a viene restituito.

Ora supponiamo che passiamo True. Poi a = Bool, in modo che il tipo di ritorno deve essere LeafConType Bool. Tuttavia, si definisce:

return = LeafCon

Quindi, return True diventa LeafCon True. Ma questo non è consentito, in quanto la definizione del tipo di LeafConType afferma che

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

Quindi, per LeafConType Bool l'argomento LeafCon deve avere tipo (Bool, Int, Int), non solo Bool. E questo è ciò che significa l'errore di compilazione: a non può essere lo stesso di (a, Int, Int). Lei afferma:

  

che voglio fare calcoli mentre i è inferiore n.

Questo significa che avrete bisogno di alcuni valori predefiniti per i e n, altrimenti sarà impossibile da definire return. Se entrambi sono pari a zero per default, allora si potrebbe definire:

return a = LeafCon (a, 0, 0)

Informazioni su (>>=):

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

Ora guardate l'implementazione (notazione leggermente diversa, stessa idea):

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

Quello che vediamo qui, è che lc viene restituito quando i >= n. Ma lc è di tipo LeafConType a, mentre f è una funzione che può restituire un valore di tipo LeafConType b, per qualsiasi b. Come risultato potrebbe essere che b non è uguale a a e quindi questi tipi non corrispondono. In conclusione, si deve seriamente porsi una domanda:

Può questo tipo di calcolo essere espresso come una monade in ogni caso?

Altri suggerimenti

Le funzioni specificati per >>= e return non soddisfano le tipologie richieste dal Monad:

return :: a -> LeafConType a

Data la dichiarazione

return = LeafCon

si dà la funzione del tipo incompatibile

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

Una dichiarazione come return 42 sarebbe quindi impossibile nel vostro monade.

Non capisco che cosa il vostro monade dovrebbe fare a tutti. In primo luogo dare un'occhiata a semplici, monadi di lavoro!

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

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

A giudicare dalla tua descrizione di ciò che si desidera che il monade da fare, penso che si desidera qualcosa di un po 'come questo:

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)

Alcuni esempi:

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

ho buttato questo insieme abbastanza rapidamente, è piuttosto brutto, e non ho controllato per vedere se si obbedisce una delle leggi Monade, in modo da utilizzare a vostro rischio e pericolo! :)

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