2016-09-10 3 views
4

Одна из вещей, которые мне больше всего нравятся в Haskell, заключается в том, как компилятор находит побочные эффекты через монады IO в сигнатурах функций. Тем не менее, кажется, легко обойти эту проверку типа, импортируя 2 GHC примитивы:Escaping monad IO

{-# LANGUAGE MagicHash #-} 

import GHC.Magic(runRW#) 
import GHC.Types(IO(..)) 

hiddenPrint ::() 
hiddenPrint = case putStrLn "Hello !" of 
    IO sideEffect -> case runRW# sideEffect of 
    _ ->() 

hiddenPrint является единицы типа, но это не вызовет побочный эффект при вызове (печатает Hello). Есть ли способ запретить эти скрытые IO (кроме доверия никому не импортировать примитивы GHC)?

+6

Я думаю, что полезность IO (и аналогичных функций безопасности) должна измеряться в «как легко заставить ее работать, если вы не хотите ее сломать», а не «как легко сломать ее, если вы хотите ее сломать» , –

+2

Кроме того, импорт 'System.IO.Unsafe' и использование' unsafePerformIO' выглядит проще;). Легко обойти, но _unsafe_. – Zeta

+0

'unsafeDupablePerformIO (IO m) = case runRW # m of (# _, a #) -> a' Это точно то же самое, я не знал этого модуля, хотя :) Я наткнулся на 'runRW #' при чтении упрощения ядро. –

ответ

7

Это цель Safe Haskell. Если вы добавите {-# Safe #-} в начало исходного файла, вам будет разрешено импортировать модули, которые либо выведены безопасно, либо помечены как {-# Trustworthy #-}. Это также накладывает некоторые незначительные ограничения на перекрывающиеся экземпляры.

3

Существует много способов, которыми вы можете нарушить чистоту в Haskell. Тем не менее, вы должны уйти от своего пути, чтобы найти их. Вот некоторые из них:

  • Импорт GHC внутренних модулей для доступа низкоуровневых примитивов
  • Использование FFI импортировать функцию C как чистый один, когда он не является чистым
  • Использование unsafePerformIO
  • Использование unsafeCoerce
  • Использование Ptr a и разыменования указателей не указывает на достоверные данные
  • Заявляя свои собственные Typeable экземпляры, и лежа, чтобы вы могли злоупотреблять cast. (Больше не возможно в недавнем GHC)
  • Использование небезопасных операций массива

Все эти и другие, не предназначены для регулярного использования. Они там, так что, если кто-то действительно, действительно уверен, может сказать компилятор «Я знаю, что делаю, не мешай мне». Выполняя это, вы берете на себя бремя доказательства - доказывая, что то, что вы делаете, безопасно.

+1

В последних версиях GHC вы не можете определить свои собственные экземпляры 'Typeable'. Ближе всего вы могли бы прийти к 'unsafeCoerce' что-то вроде' Dict (Typeable a) ', но это будет иметь только локальные эффекты. – dfeuer

+0

@dfeuer Я подозревал, что это было невозможно, поскольку автоматическое получение было реализовано. Спасибо за разъяснения. – chi