我使用函数类型感到困惑。
假设我想实现一个字典,当给出a和b时返回Maybe b。
type Dict a b = a->Maybe b
如何为此词典实现插入功能?
insertDict :: (Eq a) => a -> b -> (Dict a b)-> (Dict a b)
我想出了以下内容
insertDict x y mydict = \a->Just y
但它不正确,将丢弃以前的字典。
答案 0 :(得分:17)
您可以使用"责任链" pattern:insert函数检查结果 Dict
的参数是否与其自己的键匹配,否则它将委托上一个作为参数接收的Dict
。
type Dict a b = a -> Maybe b
insertDict :: (Eq a) => a -> b -> Dict a b -> Dict a b
-- Note that the k' is the argument of the result dict function
insertDict k v dict k' = if k == k' then Just v else dict k'
emptyDict :: Dict a b
emptyDict _ = Nothing
ghci中的一些例子:
Λ insertDict 'a' (1::Int) emptyDict $ 'a'
Just 1
Λ insertDict 'b' 2 (insertDict 'a' (1::Int) emptyDict) $ 'a'
Just 1
Λ insertDict 'b' 2 (insertDict 'a' (1::Int) emptyDict) $ 'x'
Nothing
将地图表示为函数作为第一个近似值很好,但这种表示有许多缺点:
答案 1 :(得分:11)
这是一种可以用来帮助自己编写这些函数的方法。首先,写下类型签名:
insertDict :: (Eq k) => k -> v -> Dict k v -> Dict k v
为了清楚起见,我在这里使用了k
和v
作为“密钥”和“值”。接下来,首先将实现编写为 hole :
insertDict key value dict
= _
编译器(或GHCi)应该给您一条消息,例如“找到漏洞:_ :: Dict k v
[...]相关绑定包括:dict :: Dict k v
,value :: v
,key :: k
。所以在这里你看到你可以只返回dict
,因为类型匹配,但这会忽略key
和value
。
既然你知道Dict k v
是一个函数类型,你可以通过添加一个带有另一个洞的lambda来看看编译器提供了什么:
insertDict key value dict
= \ key' -> _
现在我们有_ :: Maybe v
,value :: v
,key' :: k
,key' :: k
,dict :: Dict k v
。我们总是可以返回Just value
,但正如您所观察到的那样,这并不是我们想要的 - 它代表一个始终回答“是,该键在字典中并且其值为value
”的字典对于你问的任何钥匙! (这是一个有用的东西,能够代表,这不是我们正在写的东西。)
所以看起来我们不能仅仅取得这些进展 - 但是等等,我们也有Eq k
约束!我们可以比较的唯一两件事是key
和key'
,所以让我们使用if
将其展开为==
:
insertDict key value dict
= \ key' -> if key == key' then _1 else _2
现在编译器报告_1 :: Maybe v
和_2 :: Maybe v
。我们应该在每种情况下返回什么?让我们考虑一下如何实际使用此函数的一些示例 - 如果在插入键值对后在字典中查找键,您当然应该找到值:
(insertDict key value dict) key == Just value
----------
因此,_1
我们可以写Just value
:
insertDict key value dict
= \ key' -> if key == key' then Just value else _2
----------
如果你查找不同的键而不是你刚刚插入的那个,那么最近插入的键值对无关紧要;它应该在字典中进一步查找关键字:
(insertDict key value dict) key' == dict key' -- If key /= key'
---------
因此,_2
我们可以写dict key'
:
insertDict key value dict
= \ key' -> if key == key' then Just value else dict key'
---------
我们已经完成了! :d
在Haskell中编写时,类型导向编程和等式推理的组合非常有用,特别是对于具有有限数量的可能的多态函数(理智) )实施。