2016-05-05 3 views
-1
type InterpreterMonad = ErrorT String ((StateT (Stack EnvEval)) IO) 


argsToContext :: [DefArg] -> [CallArg] -> InterpreterMonad() 
argsToContext xs ys = argsToContext' xs ys Map.empty where 
    argsToContext' ((ArgForDefinition t name):xs) ((ArgForCall e):ys) m = get >>= \contextStack -> (argsToContext' xs ys (Map.insert name e m)) 
    argsToContext' [] [] m = get >>= \contextStack -> (put (push contextStack m)) >>= \_ -> return() 


data DefArg = 
    ArgForDefinition Type VarName 
data CallArg = 
    ArgForCall Evaluable 

Здравствуйте,Монады возвращают пустой тип: возвращение()

У меня есть проблемы с пониманием выше кусок Haskell кода

Тем более, я не могу понять, как это делает return() и почему размещен здесь.

Просьба пояснить.

+1

Похоже, что он просто игнорирует результат предыдущей операции, то есть преобразует 'm a' в' m() '. Хотя 'put' должен возвращать' m() 'так или иначе, чтобы вы могли просто удалить его. – Lee

+0

Даже в контексте, где вам нужно изменить 'm a' на' m() ', вы должны, вероятно, использовать плохо названную функцию' void', которая делает именно это или '() <$'. Любой из них будет быстрее для некоторых функторов. – dfeuer

ответ

3

return в Haskell не означает, что это означает на императивных языках, таких как C или Java. На самом деле это действительно неправильное имя, но мы застряли в нем по историческим причинам. Лучше имена будут «чистыми» или «обертываниями», что означает, что он принимает чистое значение и переносит его в монадический контекст.

Тип () известен как «единица». Он не пуст, потому что он имеет одно значение, также называемое () (отсюда и название). Однако он является пустым, потому что вы используете его, когда вы не хотите передавать какую-либо информацию: есть только одно значение, поэтому для его представления нужны нулевые биты. (Существует тип «Пустота», доступный для тех случаев, когда вы действительно не хотите, чтобы у него были какие-либо значения).

Таким образом, return() означает, что это монадическое действие обертывает единицу в монадическом контексте. По сути, это no-op: ничего не делать и не возвращать никакой информации.

В этом случае его используют в случае, когда аргументы представляют собой два пустых списка. argsToContext' выполняет работу по объединению списка DefArg с указанием CallArg. Первое определение берет начало каждого списка, делает с ним дело, а затем называет себя хвостами каждого списка. Когда хвосты являются пустыми, он вызывает вторую версию, которая помещает результирующий контекст поверх стека контекста. Если два списка имеют разную длину, тогда он выдает исключение, потому что ни один шаблон не совпадает. Если это ваш код, тогда вы должны положить в защитный футляр, частично, чтобы помочь вам отлаживать, частично, чтобы показать, что вы на самом деле задумались над этим делом, а отчасти, чтобы остановить компилятор, который вас завораживает.

«Контекст» в этом случае является переменными интерпретатора, которые хранятся в Map. Следовательно, единственным эффектом argsToContext' является добавление этих пар в контекст, а затем возврат значения «Единица». InterpreterMonad является монадическим типом, а возвращаемое значение имеет тип InterpreterMonad(), что означает, что информация не возвращается, она имеет только побочные эффекты в монадическом контексте.

На самом деле я не думаю, что вам нужно return() здесь, потому что put уже имеет тип m() для любой монады вы. Так что просто удалите >>= \_ -> return(), и я думаю, что он будет работать нормально.

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