Почему Data.Vector.Mutable read () возвращает в монаде, поскольку это неизменяемая операция? - PullRequest
5 голосов
/ 10 октября 2019

Глядя здесь http://hackage.haskell.org/package/vector-0.12.0.3/docs/Data-Vector-Mutable.html Видно, что тип чтения:

read :: PrimMonad m => MVector (PrimState m) a -> Int -> m a

Поскольку операция чтения не изменяет вектор, мой главный вопрос: почему это не так:

read :: PrimMonad m => MVector (PrimState m) a -> Int -> a

Длина изменяемого вектора также делает что-то неизменное для вектора, и его тип равен MVector s a -> Int, что выглядит нормально. Это не PrimMonad m => MVector (PrimState m) a -> m Int. Так почему же было сделано такое различие в выборе дизайна между чтением и длиной, поскольку они являются неизменяемыми операциями над вектором?

Теперь, когда я думаю об этом, может ли быть так, что ячейка, возвращаемая чтением, является ссылкойклетка внутри вектора, а не копия его данных? Если да, то как я могу красиво и дешево получить неизменный доступ к n-му элементу изменяемого вектора? Я изучаю haskell и не очень уверен в деталях.

Спасибо,

Ответы [ 2 ]

9 голосов
/ 11 октября 2019

Предположим,

read :: MVector s a -> Int -> a

, что означает read чисто. Рассмотрим

main :: IO ()
main = do
  cell <- replicate 1 'a' -- cell = ['a']
  print $ read cell 1 -- we want to print 'a'
  write cell 1 'z' -- cell = ['z']
  print $ read cell 1 -- we want to print 'z'

Что-то пошло не так: я написал read cell 1 дважды, передав одинаковые cell и 1 аргументы, поэтому два вызова должны возвращать одно и то же значение. Вот что значит для read быть чистым. Выше должно быть равно

main :: IO ()
main = do
  cell <- replicate 1 'a' -- cell = ['a']
  let contents = read cell 1 -- contents = 'a'
  print contents -- prints 'a'
  write cell 1 'z' -- cell = ['z']; definitely should not affect contents
  print contents -- prints 'a'

Но мы не хотим этого: мы хотим, чтобы read возвращало разные вещи, даже когда мы передаем одни и те же аргументы, принимая во внимание любые write s, которые могутслучилось между ними. Следовательно, read должно быть монадическим действием.

Это отличается от length. Длина вектора никогда не меняется, даже если вектор изменчив;длина фиксированная при создании. Следовательно, length является чистой функцией;не имеет значения, какие монадические действия вы выполнили между созданием вектора и запросом его длины;это всегда будет одним и тем же.

4 голосов
/ 11 октября 2019

Рассмотрим

foo = do
   ...
   x1 <- read vector 3
   write vector 3 something
   x2 <- read vector 3
   return (x1 == x2)

Если read становится не монадическим, мы можем вместо этого записать это

foo = do
   ...
   let x1 = read vector 3
   write vector 3 something
   let x2 = read vector 3
   return (x1 == x2)

, которое по прозрачности ссылок эквивалентно

foo = do
   ...
   let x1 = read vector 3
   write vector 3 something
   let x2 = x1
   return (x1 == x2)

Здесь у нас есть проблема: последний фрагмент всегда возвращает True в конце, а первый - нет. Таким образом, эти два фрагмента на самом деле не эквивалентны.

Чтение должно рассматриваться как эффект не потому, что его можно наблюдать извне (это не так), а потому, что он дает другой результат в зависимости от состояния вектора,что происходит от записи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...