得到这个:
data Cmd = PushK Int | Pop | Push Int
deriving (Eq,Show)
type StackProgram = [Cmd]
问:如何获取PushK
的Int
值?
> 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 -> Int
和p :: 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
的值。下面提取由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
进行比较,并考虑可以为Cmd
类型定义哪些类似于Data.Maybe.fromJust
、Data.Maybe.catMaybes
等的函数。