2016-04-04 9 views
1

Ich lerne immer noch Haskell und im Moment praktiziere ich Monaden. Jetzt habe ich eine LinkedList-Monade in Haskell definiert und implementiert, aber ich bin mir nicht ganz sicher, ob ich auf dem richtigen Weg bin. Der Grund, warum ich nicht sicher bin, ist die Tatsache, dass ich die Binde- oder Einheitenfunktionen in den anderen Funktionen (wie add oder getFirstItem) nicht verwende.Überprüfung von LinkedList Monad in Haskell

Dies ist mein Code so weit:

module LinkedList where 

import Control.Applicative 
import Control.Monad (ap) 

data LinkedList a = Success (a, LinkedList a) | Null | Fail String 

instance (Show a) => Show (LinkedList a) where 
    show (Success (x, previous)) = (show x) ++ " ~ " ++ (show previous) 
    show (Fail s) = "An error occured " ++ s 
    show Null = "END" 

instance Functor LinkedList where 
    fmap f (Success (x, y)) = Success (f x, fmap f y) 
    fmap f Null = Null 
    fmap f (Fail s) = Fail s 

instance Applicative LinkedList where 
    pure = return 
    (<*>) = ap 

instance Monad LinkedList where 
    return x = Success (x, Null) 
    (Success (x, xs)) >>= f = Success (getFirstItem (f x), xs >>= f) 
    (Fail s) >>= f = Fail s 
    Null >>= f = Null 

-- Get the first element from the LinkedList 
getFirstItem :: LinkedList a -> a 
getFirstItem (Success (x, xs)) = x 
getFirstItem Null = error "Cannot take first element of empty list" 
getFirstItem (Fail s) = error (show s) 

-- Get the nth element from the LinkedList 
getItem :: LinkedList a -> Integer -> a 
getItem (Success (x, xs)) n = if n == 0 then x else getItem xs (n - 1) 
getItem (Fail s) _ = error (show s) 
getItem Null _ = error "LinkedList out of bounds" 

-- Add a single element to the LinkedList 
add :: LinkedList a -> a -> LinkedList a 
add (Success (x, xs)) y = Success (x, (add xs y)) 
add Null y = Success (y, Null) 
add (Fail s) _ = error (show s) 
+0

'Fail String' sollte nicht Teil des' LinkedList a' Typs sein. Es stellt einen Fehler dar, einen gültigen Wert und keinen Wert selbst zu erstellen. – chepner

Antwort

5

Sie haben die Monade Gesetze zu überprüfen, ob Sie auf dem richtigen Weg sind, um zu sehen. Beginnen wir mit dem linken Identität Gesetz beginnen:

return a >>= f = f a 

der f Funktion nehmen lassen wie:

testFun :: Int -> LinkedList Int 
testFun x = Success (x + 2, Fail "hello") 

des return 3 >>= testFun lassen berechnen:

return 3 = Success (3, Null) 
return 3 >>= testFun = Success (5, Null) 

des testFun 3 lassen berechnen:

testFun 3 = Success (5, Fail "hello") 

Success (5, Null) ist nicht gleich Success (5, Fail "hello").

So ist es keine richtige Monade.

+0

Aha, danke! Ich habe die Monadengesetze völlig vergessen. Was ist mit meinen anderen Funktionen? Ich denke, es wäre besser, sie auch eine LinkedList zurückgeben zu lassen? –

+1

Ich denke, 'Null' und' Fail String' können zu einem einzigen Konstruktor konvergiert werden. Auch die Verwendung von 'error' im Code ist normalerweise keine gute Übung. Versuchen Sie, die Fehlervariante mit 'Maybe' oder' Eat' zu modellieren. – Sibi

+0

Die Leute spielen oft schnell und locker mit den Monadengesetzen und sagen, dass die Gesetze sich an * einige * Gleichheit halten, nicht unbedingt definitorische Gleichheit. Ich denke, eine vernünftige Vorstellung von Gleichheit könnte einfach alle versagenden Fälle als gleich betrachten. – user2407038