J'essaye d'implémenter turtle graphics dans Haskell. L'objectif est d'être en mesure d'écrire une fonction comme ceci:Turtle Graphics comme une Monade Haskell
draw_something = do
forward 100
right 90
forward 100
...
, puis l'ont produit une liste de points (peut-être avec des propriétés supplémentaires):
> draw_something (0,0) 0 -- start at (0,0) facing east (0 degrees)
[(0,0), (0,100), (-100,100), ...]
J'ai tout cela de travail dans un De façon 'normale', mais je n'ai pas réussi à l'implémenter comme une Monade Haskell et à utiliser la notation Do. Le code de base:
data State a = State (a, a) a -- (x,y), angle
deriving (Show, Eq)
initstate :: State Float
initstate = State (0.0,0.0) 0.0
-- constrain angles to 0 to 2*pi
fmod :: Float -> Float
fmod a
| a >= 2*pi = fmod (a-2*pi)
| a < 0 = fmod (a+2*pi)
| otherwise = a
forward :: Float -> State Float -> [State Float]
forward d (State (x,y) angle) = [State (x + d * (sin angle), y + d * (cos angle)) angle]
right :: Float -> State Float -> [State Float]
right d (State pos angle) = [State pos (fmod (angle+d))]
bind :: [State a] -> (State a -> [State a]) -> [State a]
bind xs f = xs ++ (f (head $ reverse xs))
ret :: State a -> [State a]
ret x = [x]
Avec ce je peux maintenant écrire
> [initstate] `bind` (forward 100) `bind` (right (pi/2)) `bind` (forward 100)
[State (0.0,0.0) 0.0,State (0.0,100.0) 0.0,State (0.0,100.0) 1.5707964,State (100.0,99.99999) 1.5707964]
et obtenir le résultat attendu. Cependant, je ne peux pas en faire une instance de Monad
.
instance Monad [State] where
...
résultats dans
`State' is not applied to enough type arguments
Expected kind `*', but `State' has kind `* -> *'
In the instance declaration for `Monad [State]'
Et si j'enveloppe la liste dans un nouvel objet
data StateList a = StateList [State a]
instance Monad StateList where
return x = StateList [x]
Je reçois
Couldn't match type `a' with `State a'
`a' is a rigid type variable bound by
the type signature for return :: a -> StateList a
at logo.hs:38:9
In the expression: x
In the first argument of `StateList', namely `[x]'
In the expression: StateList [x]
J'ai essayé diverses autres versions, mais je ne Je l'ai eu à courir comme je le voudrais. Qu'est-ce que je fais mal? Qu'est-ce que je comprends mal?
Il devrait être possible de mettre en œuvre une monade turtlegraphique, en augmentant l'historique des positions et des titres des tortues. Mais la façon dont vous essayez d'implémenter une instance de 'Monad' confond le type utilisé pour représenter les nombres dans cette histoire avec les types de valeurs en général. Vos 'ret' et' bind' concernent les calculs qui ne considèrent que les états comme des valeurs. Mais 'return' et' >> = 'devraient expliquer comment organiser les calculs concernant les valeurs de n'importe quel type, dont certaines pourraient aussi étendre la piste de la tortue. – pigworker
Si vous souhaitez que la "monade" génère une liste de points, vous pouvez choisir Writer + State plutôt que State. Writer est typiquement la "monade de l'accumulation" bien qu'elle puisse fonctionner d'autres manières. Pour progresser, vous devez également voir pourquoi les monades d'état sont des fonctions enveloppées par un 'newtype' - ce sont des fonctions de l'état actuel à une paire de nouvel état plus la réponse, pas seulement le nouvel état. Souvent, la réponse est 'unit' aka(). Par exemple, forward serait typiquement 'forward :: Float -> Turtle()' en supposant une monade appelée Turtle. –