Контекст: при рассмотрении сигнатуры функции на типичном императивном языке некоторые параметры могут быть обозначены как изменяемые ссылки, некоторые параметры могут быть обозначены как неизменяемые ссылки, некоторые параметры могут рассматриваться как простые чистые константы.
Я пытаюсь понять, как воспроизвести это в Haskell, самое главное - изменяемую / неизменяемую обработку переменных, которые зависят от состояния.
В Haskell есть несколько подходов к управлению состоянием. Один из подходов, кажется, основан на использовании _1 _ / _ 2 _ / _ 3_, который хорошо сочетается с преобразователями монад. Среди параметров функции с сохранением состояния, если я хочу явно указать, что один из них должен рассматриваться как неизменный внутри тела функции, я считаю, что ответы на этот вопрос: Создание функций только для чтения для состояния в Haskell хорошо объясните, как это сделать, используя Reader
или MonadReader
.
Другой подход к управлению состоянием (который меня больше интересует в данном случае) - это ST
. Мне нравится ST
больше, потому что он позволяет управлять более чем одной ячейкой памяти одновременно и кажется более производительным, чем State
. Проблема в том, что я не знаю, как правильно различать изменяемые / неизменяемые переменные с состоянием в ST
. Способ Reader
в этом случае не подходит. Я смотрел на пакет STMonadTrans
, который, кажется, помогает ST
работать с преобразователями монад, но я не уверен, как его использовать.
Вопрос: У вас есть простой пример функции f
, которая создает изменяемую переменную x
с newSTRef
и передает x
функции g
неизменным способом, то есть таким образом, что g
может читать x
, но не изменять x
? Если нет, есть ли обходной путь?
Замечание 1. Обходной путь может заключаться в том, чтобы заморозить изменяемые переменные перед их передачей, чтобы сделать их чистыми, однако в моем случае это неприемлемое решение, потому что замораживание может быть либо дорогостоящим, либо небезопасным, и невозможно быстро заморозить сложные структуры, такие как векторы векторов. Недопустимо и небезопасное принуждение. Я ищу безопасное решение с нулевой стоимостью выполнения.
Замечание 2: Кто-то сказал, что я могу просто прочитать ссылку, прежде чем переходить к функции, но это слишком упрощенный ответ на мой упрощенный вопрос. В более общем контексте, возможно, что нельзя readSTRef
переменную x
, прежде чем перейти к функции g
, потому что x
более сложен, как набор изменяемых массивов. Я все еще задаю свой вопрос таким простым способом, чтобы попытаться выяснить, как сделать общую вещь на простом примере.
Спасибо
do { xVal <- readSTRef x; let result = fn xVal }
не работает?xVal
- это просто значение, поэтомуfn
может вызывать его, но не изменять, поскольку параметры функции не могут быть изменены в Haskell. - person bradrn   schedule 03.06.2020fn
x
наwriteSTRef
. Если да, то код, который я дал, должен работать. Если нет, то что вы имели в виду? - person bradrn   schedule 03.06.2020readIORef
, но неwriteIORef
, тогда у вас есть неизменное значение, и, насколько я понимаю, нет смысла использовать для этогоSTRef s a
, а не простоa
. - person bradrn   schedule 03.06.2020x
более сложен, как массив, и вы хотите прочитать некоторые ячейки в нем - person jam   schedule 03.06.2020readCell :: Int -> Array a -> a
; тогда я мог бы определить чистую функциюfn
, используя это, и снова сделатьdo { array <- readSTRef arrayRef; let result = pureFnUsingReadCell array }
. (1/2) - person bradrn   schedule 03.06.2020ST
,IORef
и т. Д. Однако обычно они вам не нужны. - person Mark Seemann   schedule 03.06.2020STRef
- но в этом случае я ожидал бы, что функции будут преобразовывать изменяемый в неизменяемый (например,freeze
), что позволит вам сделатьdo { array <- freeze mutArray; let result = pureFnUsingReadCell array }
. - person bradrn   schedule 03.06.2020ST
, либо небезопасно, либо неэффективно. СState
Reader
- чистое решение. - person jam   schedule 03.06.2020criterion
) и посмотреть, действительно ли использованиеunsafeFreeze
слишком медленное, чтобы использовал. - person bradrn   schedule 03.06.2020State
, я не понимаю, почему не должно существовать чистого решения дляST
- person jam   schedule 03.06.2020newtype STArray' p s i e = STArray' (STArray s i e)
. Затем определитеdata Mutation = CanMutate | CantMutate
. Теперь, включив{-# LANGUAGE DataKinds #-}
, вы можете иметь значения какSTArray' CanMutate s i e
, так иSTArray' CantMutate s i e
. Это позволит вам определить функцию-оболочкуwriteArray :: (Ix i) => STArray' CanMutate s i e -> i -> e -> ST s ()
, которая может применяться только к изменяемым массивам. - person bradrn   schedule 03.06.2020freeze :: STArray' CanMutate s i e -> STArray' CantMutate s i e
просто перестает работать. - person bradrn   schedule 03.06.2020