#haskell
Вопрос:
У меня есть объявление функции:
iexec :: Instr -gt; Config -gt; Config iexec (LOADI x) (counter, memory, stack) = (counter 1, memory, x:stack)
с Instr и конфигурацией, являющимися новыми классами типов. Я хочу, чтобы это работало так:
gt;iexec (LOADI 5) (0, empty, []) gt;(1, fromList [], [5])
Моя проблема в том, что я не знаю, как вернуть список из памяти, все остальное работает. Я пытался сделать
iexec (LOADI x) (counter, memory, stack) = (counter 1, Map.fromList memory, x:stack)
однако я получаю ошибку, которая зависит от входных данных, но в основном она сводится к тому, что я не знаю правильного синтаксиса для этой функции, или я не могу получить доступ к списку из функции. Все, что укажет мне правильное направление, было бы полезно, спасибо.
РЕДАКТИРОВАТЬ: По запросу:
type Config = (Int, [Val] ,[Val])
где Val
находится ан Int
. Сообщение об ошибке при простом использовании памяти:
error: • Variable not in scope: empty :: [Val] • Perhaps you meant ‘mempty’ (imported from Prelude) | 9 | main = print (iexec (LOADI 5) (0, empty, []))
Комментарии:
1. Не могли бы вы включить сообщение об ошибке в свой вопрос, пожалуйста?
2. Пожалуйста, также опубликуйте определение
Config
. Я подозреваю, что это что-то вродеtype Config = (Int, [(..., ...)], [Int])
.3. Что плохого в том, чтобы просто использовать
memory
? Вы не должны использоватьfromList
здесь, такmemory
как уже естьMap
.4. @WillemVanOnsem Я не думаю, что память-это карта на данный момент, как бы я сделал ее картой?
5. @EthanGallagher: поскольку вторым параметром является a
Config
, а результатом является aConfig
, это , таким образом, означает, что если вторым элементом 3-го кортежа входных данных является aMap
, тоmemory
это карта.
Ответ №1:
Если вы напишете подпись типа, которая говорит, что вы возвращаете список, то вместо этого вы не сможете вернуть карту. Итак, ответ на вопрос в названии: «Нет, вы не можете этого сделать»..
Существует множество вариантов альтернативных планов. Одним из них было бы параметризовать ваш Config
тип. Предполагая , что вы импортировали свой любимый модуль реализации карты как M
, это будет выглядеть следующим образом:
type Config2 f = (Int, f Val, [Val]) iexec2 :: Instr -gt; Config2 [] -gt; Config2 (M.Map Int) iexec2 (LOADI x) (counter, memory, stack) = (counter 1, M.fromList (zip [0..] memory), x:stack) main = print (iexec2 (LOADI 5) (0, [], []))
Другим вариантом было бы просто изменить свой Config
тип, чтобы он всегда был картой:
type Config3 = (Int, M.Map Int Val, [Val]) iexec3 :: Instr -gt; Config3 -gt; Config3 iexec3 (LOADI x) (counter, memory, stack) = (counter 1, memory, x:stack) main = print (iexec3 (LOADI 5) (0, M.empty, []))
Есть и другие варианты, но я думаю, что эти два являются самыми чистыми.
Ответ №2:
Ответ найден и понят:
Конфигурация типа должна быть (Int, состояние, стек), где состояние и стек:
type State = Map Vname Val type Stack = [Val] type Config = (Int, State, Stack)
Таким образом, конфигурацию можно поместить в функцию iexec и использовать данные.Функциональность карты, можно использовать переменные Val и Vname, и fromList будет возвращен, поскольку состояние используется в качестве «памяти» и уже является картой.
Комментарии:
1. Чем это отличается от второго решения, которое я предложил (
Config3
там)?2. @DanielWagner технически это не так, просто лучше соответствует спецификации проекта.