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

#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 , а результатом является a Config , это , таким образом, означает, что если вторым элементом 3-го кортежа входных данных является a Map , то 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 технически это не так, просто лучше соответствует спецификации проекта.