2016-06-10 11 views
1
test :: VM.MVector s Int -> Int 
    test x = runST $ do 
    a <- return x 
    VM.read a 0 -- Type error 

Я пытаюсь понять, как не поместить все в монаду ST в одну функцию. Если я попытался изменить x или вернуть значение из него, компилятор будет жаловаться на состояние части изменяемого вектора, не совпадающего.Как изменить или прочитать измененный вектор, переданный в качестве аргумента в функции?

Может ли работать в переданных изменяемых векторах в Haskell, или я должен заморозить их в неизменяемых коллегах, прежде чем что-либо делать с ними?

Редактировать:

Настоящая ошибка.

Couldn't match type `s1' with `s' 
    `s1' is a rigid type variable bound by 
     a type expected by the context: ST s1 Int at rjb.hs:17:12 
    `s' is a rigid type variable bound by 
     the type signature for test :: VM.MVector s Int -> Int 
     at rjb.hs:16:11 
Expected type: VM.MVector 
       (Control.Monad.Primitive.PrimState (ST s1)) Int 
    Actual type: VM.MVector s Int 
Relevant bindings include 
    a :: VM.MVector s Int (bound at rjb.hs:18:5) 
    x :: VM.MVector s Int (bound at rjb.hs:17:8) 
    test :: VM.MVector s Int -> Int (bound at rjb.hs:17:3) 
In the first argument of `VM.read', namely `a' 
In a stmt of a 'do' block: VM.read a 0 

Редактировать: Следующая проверка типов проходит.

test :: VM.MVector (Control.Monad.Primitive.PrimState IO) Int -> IO (Int) 
    test x = VM.read x 0 

Я предполагаю, что я мог бы мутировать x вектор а. Итак ...

+0

Не можете добавить ошибку? – Carsten

+0

'a <- return x' является избыточным. Это просто дает вам «x» снова. – melpomene

+0

@Carsten Добавил ошибку. –

ответ

5

Возможно, вам понадобится пример. Вот основной комментарий, но я уверен, что вы найдете других в сети, если вы немного поиграете в Google.

import Control.Monad.ST 
import qualified Data.Vector.Mutable as VM 

-- This returns a reference to a vector, wrapped in the ST s monad. 
test :: ST s (VM.MVector s Int) 
test = do 
    v <- VM.new 10  -- create vector 
    VM.write v 3 2000 -- modify it 
    VM.write v 4 3000 
    x <- VM.read v 3  -- access it 
    VM.write v 4 (x+1) 
    return v    -- return it 

-- This instead returns a (wrapped) Int 
test2 :: ST s Int 
test2 = do 
    v <- test   -- call test, which performs the allocation 
    VM.read v 4   -- return v[4] 

-- This returns a plain pure Int value  
test3 :: Int 
test3 = runST test2 

Обратите внимание, что runST x может использоваться только тогда, когда тип x является политипа ST s T где T не включает в себя переменные типа s. Так монада ST достигает ссылочной прозрачности.

В более простых терминах это означает, что любой «указатель» на выделенную память никогда не должен возвращаться runST. Когда возвращается runST, каждое выделение изменчивых вещей может быть освобождено. Следовательно, типичное вычисление ST s выполняет runST только в самом конце, когда оно готово выбросить все изменчивые данные и сохранить неизменную часть. В приведенном выше примере неизменяемая часть была 4-м элементом (считая от 0, как обычно), который является неизменным Int.

Если вы не знакомы с ST s, я бы рекомендовал вам забыть о векторах на данный момент, и сделать некоторые практики с STRef s Int (ссылки на Int) и ST. Любой учебник ST будет достаточным.

+0

Право, это то, что я искал. Вот как выглядит подпись типа для монады ST. И изменяемый вектор и монада ST имеют одинаковый тип 's'. Вообще-то, что это за '' '' '' '' '' s 's' s (VM.MVector s Int) 'предполагается делать, кроме того, чтобы предотвратить случайное мутирование вектора? –

+5

@MarkoGrdinic 's' - это фиктивный тип, который« затушевывает »все« несущие указатели »вещи, такие как« STRef s Int »или« MVector s Int ». Его цель - помешать вам вернуть эти «указатели» из «runST», ничего другого - это просто доказать компилятору, что вы играли по правилам. – chi

+0

@chi IIRC. Это также должно помешать вам выполнять ненавязчиво перемежающиеся действия ST, которые работают на отдельных кусках памяти. Таким образом, вы не можете попытаться ссылаться на указатель, созданный в блоке 'foo', в то время как внутри' bar', не запуская сначала все 'foo'. – semicolon