避免 Haskell 关联列表中的条目冲突
Avoiding conflicting entries in Haskell associative list
我有以下关联列表:
myList :: [(myConcept, String)]
myList = [
(myInput, "get_input"),
(myOutput, "get_output"),
(myValues, "get_values")]
-- | Data type
data myConcept = myInput | myOutput | myValues deriving Eq
如果添加条目,我想确保列表没有任何冲突的条目。如何才能做到这一点?是否可以使用列表 Map myConcept String 来避免条目冲突?
编辑:
我可以使用以下函数来防止键冲突,但我也想防止值冲突。
addOrReplace :: Eq k => k -> v -> [(k, v)] -> [(k, v)]
addOrReplace key value list = (key,value):(filter ((key /=).fst) list)
我了解递归检查列表,但如何检查关联列表中一对的值?
checkValue :: Eq v => v -> [(k, v)] -> Bool
checkValue :: value [] = False
checkValue :: value [x] = check value of this entry?
checkValue :: value [x:xs]
| check value of this entry?
| otherwise = checkValue value xs
上面的另一个问题是 [x:xs] 它将 return False 并且不检查列表的其余部分。如何在“如果为假,继续检查列表”的位置添加 if 条件?
我怀疑 Bimap 几乎可以满足您的所有需求。您可能必须编写一个小的包装器以在重复条目上抛出运行时错误(而不是覆盖),但这应该不会太难。
import qualified Data.Map as MAP
import Data.Maybe
import qualified Data.Bimap as BIMAP
data MyConcept = MyInput | MyOutput | MyValues deriving Eq
myList :: [(MyConcept, String)]
myList = [
(MyInput, "get_input"),
(MyOutput, "get_output"),
(MyValues, "get_values")]
开始于:您的固定 checkValue 函数:
checkValue :: Eq v => v -> [(k, v)] -> Bool
checkValue str [] = False
checkValue str ((t,v):xs)
| str == v = True
| otherwise = checkValue str xs
您必须问自己的一般问题:条目在 MyConcept 中是否应该是唯一的:
(a) schould [(MyInput, "value1"), (MyInput, "value2")] be allowed?
所以我假设:
(b) MyValues is the only identifier which can hold actual values
-> 否则只检查值(= 字符串部分)是没有意义的...
选项 1.1:地图
假设 (a) 不允许:
-- additionally needed:
instance Ord MyConcept where
compare m1 m2
| m1 == m2 = EQ
| otherwise = LT -- not good but practical
type List_Map1 = MAP.Map MyConcept (MyConcept, String)
add1 :: String -> List_Map1 -> List_Map1
add1 str list = if isNothing value
then MAP.insert MyValues (MyValues, str) list
else error "insert here your prefered runtime error message"
where
value = MAP.lookup MyValues list
选项 1.2:地图
假设 (a) 是允许的:
type List_Map2 = MAP.Map String (MyConcept, String)
add2 :: String -> List_Map2 -> List_Map2
add2 str list = if isNothing value
then MAP.insert str (MyValues, str) list
else error ""
where
value = MAP.lookup str list
选项 2:BiMap
type List_Bimap = BIMAP.Bimap MyConcept (MyConcept, String)
add3 :: String -> List_Bimap -> List_Bimap
add3 str list
| isNothing value = BIMAP.insert MyValues (MyValues, str) list
| str == snd (fromJust value) = error "insert here your prefered runtime error message"
-- Change next line to allow (a)
| otherwise = error "insert here your prefered runtime error message"
where
value :: Maybe (MyConcept, String)
value = BIMAP.lookup MyValues list
最后,如果您更喜欢简单的列表作为输出:
list1 :: String -> List_Map1 -> [(MyConcept, String)]
list1 s l = map snd $ MAP.toList $ add1 s l
list2 :: String -> List_Map2 -> [(MyConcept, String)]
list2 s l = map snd $ MAP.toList $ add2 s l
list3 :: String -> List_Bimap -> [(MyConcept, String)]
list3 s l = map snd $ BIMAP.toList $ add3 s l
我有以下关联列表:
myList :: [(myConcept, String)]
myList = [
(myInput, "get_input"),
(myOutput, "get_output"),
(myValues, "get_values")]
-- | Data type
data myConcept = myInput | myOutput | myValues deriving Eq
如果添加条目,我想确保列表没有任何冲突的条目。如何才能做到这一点?是否可以使用列表 Map myConcept String 来避免条目冲突?
编辑:
我可以使用以下函数来防止键冲突,但我也想防止值冲突。
addOrReplace :: Eq k => k -> v -> [(k, v)] -> [(k, v)]
addOrReplace key value list = (key,value):(filter ((key /=).fst) list)
我了解递归检查列表,但如何检查关联列表中一对的值?
checkValue :: Eq v => v -> [(k, v)] -> Bool
checkValue :: value [] = False
checkValue :: value [x] = check value of this entry?
checkValue :: value [x:xs]
| check value of this entry?
| otherwise = checkValue value xs
上面的另一个问题是 [x:xs] 它将 return False 并且不检查列表的其余部分。如何在“如果为假,继续检查列表”的位置添加 if 条件?
我怀疑 Bimap 几乎可以满足您的所有需求。您可能必须编写一个小的包装器以在重复条目上抛出运行时错误(而不是覆盖),但这应该不会太难。
import qualified Data.Map as MAP
import Data.Maybe
import qualified Data.Bimap as BIMAP
data MyConcept = MyInput | MyOutput | MyValues deriving Eq
myList :: [(MyConcept, String)]
myList = [
(MyInput, "get_input"),
(MyOutput, "get_output"),
(MyValues, "get_values")]
开始于:您的固定 checkValue 函数:
checkValue :: Eq v => v -> [(k, v)] -> Bool
checkValue str [] = False
checkValue str ((t,v):xs)
| str == v = True
| otherwise = checkValue str xs
您必须问自己的一般问题:条目在 MyConcept 中是否应该是唯一的:
(a) schould [(MyInput, "value1"), (MyInput, "value2")] be allowed?
所以我假设:
(b) MyValues is the only identifier which can hold actual values
-> 否则只检查值(= 字符串部分)是没有意义的...
选项 1.1:地图 假设 (a) 不允许:
-- additionally needed:
instance Ord MyConcept where
compare m1 m2
| m1 == m2 = EQ
| otherwise = LT -- not good but practical
type List_Map1 = MAP.Map MyConcept (MyConcept, String)
add1 :: String -> List_Map1 -> List_Map1
add1 str list = if isNothing value
then MAP.insert MyValues (MyValues, str) list
else error "insert here your prefered runtime error message"
where
value = MAP.lookup MyValues list
选项 1.2:地图 假设 (a) 是允许的:
type List_Map2 = MAP.Map String (MyConcept, String)
add2 :: String -> List_Map2 -> List_Map2
add2 str list = if isNothing value
then MAP.insert str (MyValues, str) list
else error ""
where
value = MAP.lookup str list
选项 2:BiMap
type List_Bimap = BIMAP.Bimap MyConcept (MyConcept, String)
add3 :: String -> List_Bimap -> List_Bimap
add3 str list
| isNothing value = BIMAP.insert MyValues (MyValues, str) list
| str == snd (fromJust value) = error "insert here your prefered runtime error message"
-- Change next line to allow (a)
| otherwise = error "insert here your prefered runtime error message"
where
value :: Maybe (MyConcept, String)
value = BIMAP.lookup MyValues list
最后,如果您更喜欢简单的列表作为输出:
list1 :: String -> List_Map1 -> [(MyConcept, String)]
list1 s l = map snd $ MAP.toList $ add1 s l
list2 :: String -> List_Map2 -> [(MyConcept, String)]
list2 s l = map snd $ MAP.toList $ add2 s l
list3 :: String -> List_Bimap -> [(MyConcept, String)]
list3 s l = map snd $ BIMAP.toList $ add3 s l