Дело Let
Как сказали Зигмонд и Вагнер, (>>=)
- правильный инструмент для работы.Давайте посмотрим на типы:
(>>=) :: m a -> (a -> m b) -> m b
update :: Variable -> Int -> m ()
evalIntExp i :: m Int
v :: Variable
Можете ли вы придумать способ объединить их в ожидаемый тип m ()
?Помните, что вы можете частично применить функцию, чтобы получить обратно функцию, которая принимает меньше аргументов.
Случай Seq
Давайте снова посмотрим на типы.
У нас есть два значения типа m ()
, (evalComm c1
и evalComm c2
) и мы хотим объединить их в значение типа m ()
.Мы можем снова использовать >>=
, создав функцию, которая игнорирует ее аргумент:
Seq c1 c2 -> (evalComm c1) >>= (\x -> (evalComm c1))
Однако это такой распространенный сценарий, поэтому для него уже есть встроенная функция:
(>>) :: m a -> m b -> m b
Seq c1 c2 -> evalComm c1 >> evalComm c1
Давайте посмотрим на ваш предыдущий код
liftM2 (:) :: m a -> m [a] -> m [a]
У вас нет списков, поэтому это бесполезно.
liftM2 :: (a -> b -> c) -> m a -> m b -> m c
Это можно использовать, если a = b = c = ()
,но это излишне сложно по сравнению с использованием >>
.Тем не менее, я призываю вас попробовать это в качестве упражнения.Как бы выглядела функция типа () -> () -> ()
?
return :: a -> m a
Это используется, когда у вас есть чистое значение и вам нужно преобразовать его в монадическое значение, поэтому нет необходимости использовать его здесь.Результат будет иметь двойной тип m (m ())
, который вам не подходит.
Заключительные слова
Как вы можете видеть, типы могут быть очень полезны при написании программ на языке Haskell.Всякий раз, когда вам интересно, какие вещи можно комбинировать, посмотрите на типы.Вы можете проверить, какой тип выражения имеет, набрав :t <expression>
в GHCi.