segunda-feira, 20 de julho de 2009

ICFP 2009 - a máquina virtual - parte II

Como prometido, vou explicar a segunda mônada existente no código da máquina virtual. Observem o código abaixo:

       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 -> Double
Peraí, 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:

Postagens populares