访问自定义数据类型 - Lambda 函数应用程序顺序



得到这个:

data Cmd = PushK Int | Pop | Push Int
deriving (Eq,Show)
type StackProgram = [Cmd]

问:如何获取PushKInt值?


> 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'

有人有解决方案吗?

通过使用模式匹配或定义记录语法(在这种情况下,Haskell自己生成getters(将值从数据构造函数中解包出来。

模式匹配

由于此处的类型定义为记录,因此我们必须使用模式匹配:

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

并且可能需要处理另一个数据构造函数的情况。

我们还可以使用 lambda 表达式执行此模式匹配:

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

记录

我们还可以将命令定义为记录:

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

现在 Haskell 自动生成了两个函数k :: Cmd -> Intp :: Cmd -> Int,所以在这种情况下我们可以编写:

k (PushK 5)

这将返回5.

(_ x -> x) PushK 5为什么回来5

在哈斯克尔,职能是一等公民。这意味着您可以将函数作为参数传递,并将它们作为结果返回。你在这里没有建造Cmd.

事实上PushK是一个数据构造函数和一个函数(类型为Int -> Cmd(,因此你用两个参数调用 lambda 表达式:第一个是pushK,第二个是5。您只需省略第一个参数,然后重新调整第二个x

但它因此衍生为:

(y x -> x) PushK 5
=  ((y -> (x -> x)) PushK) 5    -- (more verbose version)
-> (x -> x) 5
-> 5

您可能希望定义单个同胚来解构任意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的值。下面提取由PushKPush包装的值,并用Just重新包装它(PushK做一些额外工作的函数只是为了显示PushKPush之间的差异(,并将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

cmdCataData.Maybe.maybe进行比较,并考虑可以为Cmd类型定义哪些类似于Data.Maybe.fromJustData.Maybe.catMaybes等的函数。

最新更新