Доступ к самоопределенным типам данных - порядок применения функции Lambda - PullRequest
0 голосов
/ 26 мая 2018

Получил это:

data Cmd = PushK Int | Pop | Push Int
         deriving (Eq,Show)

type StackProgram = [Cmd]

Вопрос: Как мне получить доступ к значению Int PushK?


> head [PushK 5, Pop]
PushK 5  -- Great!

> (\_ x -> x)PushK 5
5 -- Great!

> (\_ x -> x)(head [PushK 5, Pop])
Couldn't match expected type `t1 -> t' with actual type `Cmd'

Любойесть решение?

Ответы [ 2 ]

0 голосов
/ 26 мая 2018

Вы можете определить один катаморфизм для деконструкции произвольного Cmd значения.

cmdCata :: (Int -> a)  -- Function to apply to x in (PushK x)
        -> a           -- Value to replace Pop
        -> (Int -> a)  -- Function to apply to x in (Push x)
        -> Cmd         -- The value to deconstruct
        -> a           -- The result
cmdCata f _ _ (PushK x) = f x
cmdCata _ x _ Pop       = x
cmdCata _ _ f (Push x)  = f x

Требуется две функции и значение по умолчанию (для Pop) дляпревратить любое Cmd значение в значение типа a.Следующее извлекает значение, заключенное в PushK или Push, и переворачивает его с помощью Just (функция для PushK выполняет небольшую дополнительную работу, чтобы показать разницу между PushK и Push), и заменяетPop с Nothing.

> cmdCata (Just . (+3)) Nothing Just (PushK 5)
Just 8  -- 5 + 3
> cmdCata (Just . (+3)) Nothing Just Pop
Nothing
> cmdCata (Just . (+3)) Nothing Just (Push 20)
Just 20

Или, если вам просто нужно целое число, и значение по умолчанию для Pop подойдет:

> cmdCata id 0 id (PushK 5)
5
> cmdCata id 0 id Pop
0
> cmdcata id 0 id (Push 3)
3

Сравните cmdCata с Data.Maybe.maybe, и подумайте, какие функции, аналогичные Data.Maybe.fromJust, Data.Maybe.catMaybes и т. Д., Могут быть определены для вашего типа Cmd.

0 голосов
/ 26 мая 2018

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

Сопоставление с образцом

Так как здесь тип не определен как запись, нам, таким образом, необходимо использовать сопоставление с образцом:

getK :: Cmd -> Int
getK (PushK x) = x
-- ...

и, возможно, вам необходимо обработать случаидругой конструктор данных.

Мы также можем выполнить сопоставление этого шаблона с лямбда-выражением:

(\(PushK x) -> x) (PushK 5)

Записи

Мы также можем определить команду как запись:

data Cmd = PushK { k :: Int } | Pop | Push { p :: Int } deriving (Eq,Show)

Теперь Haskell автоматически сгенерировал две функции k :: Cmd -> Int и p :: Cmd -> Int, поэтому в этом случае мы можем написать:

k (PushK 5)

, который вернет 5.

Почему (\_ x -> x) PushK 5 вернул 5?

В Haskell функции граждан первого класса .Это означает, что вы можете передавать функции в качестве аргументов, возвращать их как результат.Вы здесь не создали Cmd.

На самом деле PushK - это конструктор данных , и функцию (с типом Int -> Cmd), вытаким образом, называется лямбда-выражение с двумя параметрами: первое - pushK, а второе - 5.Вы просто пропускаете первый параметр и повторно вводите второй x.

Но он, таким образом, выводится как:

   (\y x -> x) PushK 5
=  ((\y -> (\x -> x)) PushK) 5    -- (more verbose version)
-> (\x -> x) 5
-> 5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...