Почему numCapabilities является чистой функцией?
В библиотеке concurrency GHC.Conc есть функция numCapabilities
. Его тип numCapabilities :: Int
, и он фактически возвращает некоторое число, которое вы передали с помощью флага командной строки (например, 5
, если параметры +RTS -N 5
).
Однако getArgs
(тип: IO [String]
) делает практически то же самое (он возвращает непараметрированные аргументы без запуска), но не является чистой функцией.
Если единственным оправданием является то, что numCapabilities
часто требуется в чистом коде, каким образом не нужны другие параметры командной строки в чистом коде?
Мне что-то не хватает или это numCapabilities
недостаток дизайна, или мне разрешено писать следующего монстра?
myGetArgs = unsafePerformIO getArgs
Ответы
Ответ 1
Я видел очень разные мнения о том, что делать в таких ситуациях. Некоторые считают, что значения, которые могут различаться между компиляторами, не должны быть чистыми, а некоторые считают, что до тех пор, пока значение не изменится во время вашей локальной локализации (то есть после некоторой "конфигурации" "setup" в main
), он должен быть чистым.
Пакет base
, похоже, поселился на средней земле. numCapabilities
не будет (насколько мне известно) изменяться во время выполнения, но getArgs
может.
Это потому, что есть функция withArgs
, которая изменяет аргументы, которые вы получаете через getArgs
. Итак, это отвечает на это.
Ответ 2
Боже мой. Если вы посмотрите на определение numCapabilities
, вы увидите, что это просто:
numCapabilities :: Int
numCapabilities = unsafePerformIO $ getNumCapabilities
а следующие сеансы ghci иллюстрируют проблему:
[[email protected] ~]$ ghci
GHCi, version 7.4.2: http://www.haskell.org/ghc/ :? for help
Loading [...]
ghci> :m +GHC.Conc
ghci> numCapabilities
1
ghci> setNumCapabilities 2
ghci> numCapabilities
1
ghci> :q
Leaving GHCi.
[[email protected] ~]$ ghci
GHCi, version 7.4.2: http://www.haskell.org/ghc/ :? for help
Loading [...]
ghci> :m +GHC.Conc
ghci> setNumCapabilities 2
ghci> numCapabilities
2
Это определенно плохо - значение numCapabilities
зависит от того, когда оно оценивается в отношении любых вызовов setNumCapabilities
, которые могут существовать в вашей программе. Обратите внимание, что в первом сеансе numCapabilities
оставался согласованным, поскольку IO
выполняется только при первом его вычислении. Однако при наличии вставки (имя не отмечено NOINLINE или что-то еще) даже это может быть неверно - вы могли бы в принципе получить два разных значения из двух вхождений numCapabilities
(хотя на практике я не смог чтобы это произошло).
Итак, ответ заключается в том, что numCapabilities
не является чистой функцией, но ошибочно помечен как таковой пресловутой задней дверью unsafePerformIO
.
Ответ 3
Я бы сказал, что это ошибка, но это зависит от того, что думает о чистоте. См. Сообщение Понятия о чистоте в Haskell и его обсуждение. Проще говоря, аргумент post состоит в том, что типы имеют смысл, и нет места в значении Int
для чего-то вроде numCapabilities
, который зависит от исполнения.
Ответ 4
numCapabilities
дает начальное значение getNumCapabilities
, так или иначе присутствует аргумент флага RTS -N, поэтому тип должен быть тем же.
Вы пробовали это с более высоким номером, чем ваш компьютер макс. одновременные потоки?
$ ghci +RTS -N99
GHCi, version 7.4.2: http://www.haskell.org/ghc/ :? for help
Prelude> :m +GHC.Conc
Prelude GHC.Conc> numCapabilities
99
Prelude GHC.Conc> getNumCapabilities
99 !!!