2013-12-02 4 views
6

Учитывая этот фрагмент кода:Почему я не могу принудительно выполнить операцию ввода-вывода с помощью seq?

someFunction x = print x `seq` 1 

main = do print (someFunction "test") 

почему не print x печати test когда код выполняется?

$./seq_test 
1 

Если я заменить его error я могу проверить, что левый операнд seqявляется действительно оценены.

Как я мог достичь своей ожидаемый результат:

test 
1 

изменения только someFunction?

+2

Оценка операции ввода-вывода не совпадает с ее выполнением. Нет никакого способа сделать someFunction делать то, что вы хотите, потому что если вы хотите использовать 'print' в нем, он должен быть в монаде IO, и вы не сможете распечатать его результат (без изменения основного). – fjh

+1

Интересно, почему нижняя сторона? Я верю, что мой вопрос - вполне правильный вопрос. – Bakuriu

ответ

10

Оценка IO Действие ничего не делает. Это верно!

Если вам нравится, значения IO являются просто «инструкциями». Итак, все, что вы делаете с этим seq, заставляет программу быть уверенной в том, что of должно быть выполнено, если действовало фактически . И использование действия не имеет никакого отношения к оценке, это означает монадически привязав его к вызову main. Но поскольку, как вы говорите, someFunction является функцией с неравномерной подписью, которая не может произойти здесь.

Что вы можете сделать ... но не, является

import Foreign 

someFunction x = unsafePerformIO (print x) `seq` 1 

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

Правильное решение изменить подпись монадическими:

someFunction :: Int -> IO Int 
someFunction x = do 
    print x 
    return 1 

main = do 
    y <- someFunction "test" 
    print y 

И, как это происходит, программа, как уверен, насколько это возможно в любом случае, даже без seq. Выполнение действия можно получить только с помощью более подробной информации.

+0

Итак, вы говорите, что если библиотеке требуется функция с определенной немонодической сигнатурой, в Haskell нет абсолютно никакого способа безопасно добавлять любой вывод во время его выполнения и продолжать использовать библиотеку? – Bakuriu

+3

Да, это правильно и намеренно. Нравится это или ненавижу. (Опять же, для отладки есть 'Debug.Trace', но для чего-то другого, кроме отладки, это действительно так же опасно, как и любой другой способ добиться выхода внутри чистой функции.) - Серьезно, если вы напишете идиоматический Haskell, вы будете гораздо меньше _need_ для такого ad-hoc ведения журнала, чем на других языках. – leftaroundabout

+0

Я согласен, если бы библиотеки имели хорошую документацию об их монадических особенностях. Например. Alex and Happy do * not * предоставляют хорошую документацию, и некоторые пользователи даже слышали, что некоторые из документов на самом деле ошибочны (что хуже, чем отсутствие документации). Если у меня есть * требование * об этом виде вывода, мне нужно будет возобновить метод do-random-change-and-guess-the-implementation, чтобы использовать их. Если вы знаете, как их использовать, ответьте на мой другой вопрос. – Bakuriu

1

seq оценил выражения в слабой форме головы, которая является просто самым внешним конструктором (или лямбдой). Выражение print x уже находится в WHNF, поэтому seq ничего не делает.

Вы можете получить результат, который вы ищете, с помощью функции Debug.Trace.trace.

+2

Выражение 'print x', конечно же, еще не указано в WHNF. – kosmikus

+0

Не имеет значения, находится ли это в WHNF для целей ввода-вывода. - «trace» - хорошее предложение - хотя, как говорит имя модуля, действительно просто для целей отладки. – leftaroundabout

+0

@leftaroundabout Я знаю, что это не важно для результата. Но это сложные проблемы, и лучше быть точным. – kosmikus

 Смежные вопросы

  • Нет связанных вопросов^_^