gpt4 book ai didi

haskell - 用仿函数和非仿函数定义一个类

转载 作者:行者123 更新时间:2023-12-01 09:31:13 25 4
gpt4 key购买 nike

我想定义一个类 m 提供仿函数操作像这样的类型签名:

映射::(a -> b) -> m a -> m b

不过,我还需要一些其他非仿函数操作。我会喜欢写一些类似的东西:

class MyMap m where
type Key m
type Value m
keys :: m -> [Key m]
elems :: m -> [Value m]
mapify :: (a -> b) -> m a -> m b -- WON'T WORK!!!

我明白为什么这行不通。我想出的解决方案是把它分成两个类,一个是仿照 Functor 的“普通”一加一。

{-# LANGUAGE TypeFamilies #-}

import qualified Data.Map.Lazy as M

class MyMap m where
type Key m
type Value m
keys :: m -> [Key m]
elems :: m -> [Value m]

class MyMapF m where
mapify :: (a -> b) -> m a -> m b

instance MyMap (M.Map k v) where
type Key (M.Map k v) = k
type Value (M.Map k v) = v
keys = M.keys
elems = M.elems

instance MyMapF (M.Map k) where
mapify = M.map

这很好,但有更好的方法吗?


编辑:我真的很喜欢 sabauma 提出的解决方案。但是,当我尝试创建一个使用此类的函数时,我无法得到类型签名。

doSomething
:: (MyMap m1, MyMap m2, Container m1 ~ Container m2) => -- line 22
(Value m1 -> Value m2) -> m1 -> m2 -- line 23
doSomething f m = mapify f m -- line 24

我得到的错误是:

../Amy3.hs:22:6:
Couldn't match type `b0' with `Value (Container m0 b0)'
`b0' is untouchable
inside the constraints (MyMap m1,
MyMap m2,
Container m1 ~ Container m2)
bound at the type signature for
doSomething :: (MyMap m1, MyMap m2, Container m1 ~ Container m2) =>
(Value m1 -> Value m2) -> m1 -> m2
Expected type: a0 -> b0
Actual type: Value m1 -> Value m2

../Amy3.hs:24:19:
Could not deduce (m2 ~ Container m0 b0)
from the context (MyMap m1, MyMap m2, Container m1 ~ Container m2)
bound by the type signature for
doSomething :: (MyMap m1, MyMap m2, Container m1 ~ Container m2) =>
(Value m1 -> Value m2) -> m1 -> m2
at ../Amy3.hs:(22,6)-(23,38)
`m2' is a rigid type variable bound by
the type signature for
doSomething :: (MyMap m1, MyMap m2, Container m1 ~ Container m2) =>
(Value m1 -> Value m2) -> m1 -> m2
at ../Amy3.hs:22:6
In the return type of a call of `mapify'
In the expression: mapify f m
In an equation for `doSomething': doSomething f m = mapify f m

../Amy3.hs:24:28:
Could not deduce (m1 ~ Container m0 a0)
from the context (MyMap m1, MyMap m2, Container m1 ~ Container m2)
bound by the type signature for
doSomething :: (MyMap m1, MyMap m2, Container m1 ~ Container m2) =>
(Value m1 -> Value m2) -> m1 -> m2
at ../Amy3.hs:(22,6)-(23,38)
`m1' is a rigid type variable bound by
the type signature for
doSomething :: (MyMap m1, MyMap m2, Container m1 ~ Container m2) =>
(Value m1 -> Value m2) -> m1 -> m2
at ../Amy3.hs:22:6
In the second argument of `mapify', namely `m'
In the expression: mapify f m
In an equation for `doSomething': doSomething f m = mapify f m
Failed, modules loaded: none.

最佳答案

一种可能性是使用另一个关联的“容器”类型编码输入。

import qualified Data.Map.Lazy as M

class MyMap m where
type Key m
type Value m
type Container m :: * -> *
keys :: m -> [Key m]
elems :: m -> [Value m]
mapify :: (a -> b) -> Container m a -> Container m b

instance MyMap (M.Map k v) where
type Key (M.Map k v) = k
type Value (M.Map k v) = v
type Container (M.Map k v) = M.Map k
keys = M.keys
elems = M.elems
mapify = M.map

MapContainerMap k,因此您将Map 及其关联的键类型。这样,您的 mapify 功能就会提升您的功能进入容器。是否“更好”取决于您,我猜,但它确实减少了类型类的数量。你不应该您的示例需要 MyMapF 类,因为 MyMapF 与标准 Functor 类型类。

好的,这个错误可以通过修改mapify的定义来解决略。

class MyMap m where
type Key m
type Value m
type Container m :: * -> *
keys :: m -> [Key m]
elems :: m -> [Value m]
-- mapify :: (a -> b) -> Container m a -> Container m b

-- Make sure the type-checker knows that m2 is just the container of m with
-- a different value
mapify :: (MyMap m2, m2 ~ Container m (Value m2)) => (Value m -> Value m2) -> m -> m2


instance MyMap (M.Map k v) where
type Key (M.Map k v) = k
type Value (M.Map k v) = v
type Container (M.Map k v) = M.Map k
keys = M.keys
elems = M.elems
mapify = M.map

doSomething
:: (MyMap m1, MyMap m2, m2 ~ Container m1 (Value m2)) =>
(Value m1 -> Value m2) -> m1 -> m2
doSomething f m = mapify f m

这将进行类型检查。我认为问题只是类型检查器需要一个更强烈的暗示,你所做的只是改变 MyMapValue实例,无需更改底层容器。

关于haskell - 用仿函数和非仿函数定义一个类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15162154/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com