函数作为haskell中的类型

时间:2018-02-24 11:28:16

标签: haskell

我使用函数类型感到困惑。

假设我想实现一个字典,当给出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

但它不正确,将丢弃以前的字典。

2 个答案:

答案 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

将地图表示为函数作为第一个近似值很好,但这种表示有许多缺点:

  • 搜索值的复杂性是键的数量是线性的。
  • 功能很漂亮"不透明",这意味着如果您使用了data type,就无法检查或序列化地图。

答案 1 :(得分:11)

这是一种可以用来帮助自己编写这些函数的方法。首先,写下类型签名:

insertDict :: (Eq k) => k -> v -> Dict k v -> Dict k v

为了清楚起见,我在这里使用了kv作为“密钥”和“值”。接下来,首先将实现编写为 hole

insertDict key value dict
  = _

编译器(或GHCi)应该给您一条消息,例如“找到漏洞:_ :: Dict k v [...]相关绑定包括:dict :: Dict k vvalue :: vkey :: k。所以在这里你看到你可以只返回dict,因为类型匹配,但这会忽略keyvalue

既然你知道Dict k v是一个函数类型,你可以通过添加一个带有另一个洞的lambda来看看编译器提供了什么:

insertDict key value dict
  = \ key' -> _

现在我们有_ :: Maybe vvalue :: vkey' :: kkey' :: kdict :: Dict k v。我们总是可以返回Just value,但正如您所观察到的那样,这并不是我们想要的 - 它代表一个始终回答“是,该键在字典中并且其值为value”的字典对于你问的任何钥匙! (这是一个有用的东西,能够代表,这不是我们正在写的东西。)

所以看起来我们不能仅仅取得这些进展 - 但是等等,我们也有Eq k约束!我们可以比较的唯一两件事是keykey',所以让我们使用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中编写时,类型导向编程等式推理的组合非常有用,特别是对于具有有限数量的可能的多态函数(理智) )实施。