Я хочу что-то вродеПрактические последствия runST против unsafePerformIO
f :: [forall m. (Mutable v) (PrimState m) r -> m()] -> v r -> v r -- illegal signature
f gs x = runST $ do
y <- thaw x
foldM_ (\_ g -> g y) undefined gs -- you get the idea
unsafeFreeze y
Я по существу в том же положении, я был в this question где Витус комментировал:
[I] F вы хотите сохранить полиморфный функции внутри какой-либо структуры, вам нужен либо специализированный тип данных (например, newtype I = I (forall a. a -> a)) или ImpredicativeTypes.
Также см. this question. Проблема в том, что это оба действительно уродливые решения. Итак, я придумал третью альтернативу, которая заключается в том, чтобы избежать полиморфизма вообще, запустив то, что «должно» быть вычислением ST
в IO
. Таким образом f
становится:
f :: [(Mutable v) RealWorld r -> IO()] -> v r -> v r
f gs x = unsafePerformIO $ do
y <- thaw x
foldM_ (\_ g -> g y) undefined gs -- you get the idea
unsafeFreeze y
Я чувствую себя немного грязным для перехода на unsafe
IO
маршрута сравнивается с «безопасным» ST
маршрута, но если моя альтернативой является оберткой или непредикативными типами ... Видимо, I'm not alone.
Есть ли причины, по которым я не должен использовать unsafePerformIO
здесь? В этом случае, действительно ли это небезопасно? Есть ли соображения производительности или что-то еще, о чем я должен знать?
-------------- EDIT ----------------
Ответ ниже показывает мне, как обойти эта проблема в целом, что здорово. Но меня все еще интересует исходный вопрос (implicaitons of runST
vs unsafePerformIO
при использовании изменяемых векторов) для образовательных целей.
Мне любопытно, почему вы думаете, что коробки нового типа являются таким уродливым решением? Это, откровенно говоря, упрощает чтение кода, «PolyModifier» легче понять, чем 'forall m. (Mutable v) (PrimState m) r -> m() '. Помимо этого, вы отказываетесь от некоторых заверений, которые дают вам системы типов. Трудно сказать, есть ли у вас здесь, вы не показали нам весь код. Но теперь вы делаете утверждения типа «x никогда больше не будете снова просматриваться», так как вы просто сбиваете чистую структуру – jozefg
Конечно, подпись для функции * one * лучше, но везде я называю эту функцию, я буду иметь «отобразить PM» в список функций. Мне также не нравилось обертывать что-то, у которого нет причин быть обернутым с точки зрения абстракции: это просто функция, ничего особенного в этом. – crockeea
У меня были некоторые подобные ситуации при работе с изорекурсивными типами, и у вас есть * для использования нового типа. Это обычная практика и в объективе. Я бы взял это на unsafePeformIO, нажатие клавиш <часы отладки. – jozefg