In Haskell, ho un contenitore simile:Come modificare impuritamente uno stato associato a un oggetto?
data Container a = Container { length :: Int, buffer :: Unboxed.Vector (Int,a) }
Questo contenitore è un albero appiattito. L'accessore (!)
esegue una ricerca binaria (log(N)
) attraverso il vettore per trovare il bucket corretto in cui è memorizzato lo index
.
(!) :: Container a -> Int -> a
container ! index = ... binary search ...
Da accessi consecutivi sono suscettibili di essere nello stesso bucket, questo potrebbe essere ottimizzato nel modo seguente:
if `index` is on the the last accessed bucket, skip the search
Il punto difficile è la parte last accessed bucket
. In JavaScript, modificherei impuramente una variabile nascosta sull'oggetto contenitore.
function read(index,object){
var lastBucket = object.__lastBucket;
// if the last bucket contains index, no need to search
if (contains(object, lastBucket, index))
var bucket = lastBucket;
// if it doesn't
else {
// then we search the bucket
var bucket = searchBucket(index,object);
// And impurely annotate it on the container, so the
// next time we access it we could skip the search.
container.__lastBucket = bucket;
}
return object.buffer[bucket].value;
}
Dal momento che questo è solo l'ottimizzazione ed il risultato è lo stesso indipendentemente dal ramo preso, credo che non si rompe la trasparenza referenziale. Come è possibile, in Haskell, modificare impuriosamente uno stato associato a un valore di runtime?
~
ho pensato in 2 possibili soluzioni.
A, hashmap mutabile globale che collega i puntatori al valore
lastBucket
, e utilizzare unsafePerformIO di scrivere su di esso. Ma avrei bisogno di un modo per ottenere il puntatore di runtime di un oggetto, o almeno un id univoco di qualche tipo (come?).Aggiungi un campo in più per
Container
,lastBucket :: Int
, e in qualche modo impurely modificare entro(!)
, e ritengono che campo interno (perché ovviamente rompere trasparenza referenziale).
Per la seconda possibilità, si consiglia di utilizzare 'lastBucket :: IORef Int' invece, e usare' unsafePerformIO' per "modificarlo impuremente". Il tuo codice JS non gestisce il fatto che '__lastBucket' possa essere modificato da un'altra chiamata' read() 'da un altro thread, quindi ha un valore diverso a' if' e a '='. –
@ Xicò ovviamente, grazie! Vorrei poterlo nascondere, però, perché non fa parte dell'API. Inoltre, quello che hai detto è vero. Ma non ho bisogno di serrature qui, giusto? Basta memorizzare '__lastBucket' in una variabile all'inizio. (JS non ha discussioni ...). Modifica: aggiornato l'OP. – MaiaVictor
Attenzione ai thread se si decide di utilizzare trucchi non sicuri. – chi