dType op r1 r2 ip (st,mem) = let !result=(liftM2 op (!-! r1) (!-! r2)) mem in
(st,insert ip result mem)
Esta função implementa as instruções de dois operandos da máquina virtual. Essencialmente, essa função deve ler os dois valores da memória endereçados por r1 e r2, executar a operação e escrever o resultado na posição ip.
A parte de escrever na memória é, simplesmente, uma chamada a insert. Mas notem a declaração de result. A par de usar o bang-pattern (redundante, visto que insert já é estrito nos parâmetros), estou usando liftM2. Essa função possui como tipo:
liftM2 :: Monad m => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
ou seja: dada uma função de dois argumentos, liftM2 a transforma em uma função de duas mônadas, com comportamento equivalente. Vamos olhar rápidamente a declaração de (!-! r1), segundo parâmetro usado em liftM2.
(!-! r2) :: M.IntMap Double -> DoublePeraí, mas Data.IntMap não é uma mônada! O que liftM2 está fazendo então? Se olharmos rapidamente Control.Monad.Instances, encontraremos que existe uma instância de mônada definida para ((->) r), ou seja, funções que recebem parâmetro do tipo r e retornam alguma outra coisa!
Analisando então a função, vemos que liftM2 op (!-! r1) (!-!r2) é uma mônada contendo um Double, e essa mônada é uma função que recebe um Data.IntMap. Ou seja, o tipo de liftM2 op (!-! r1) (!-! r2) é Data.IntMap->Double! Não é lindo??
No próximo post, vou, finalmente, mostrar meu simulador de transferência de órbitas. Até lá!
Nenhum comentário:
Postar um comentário