避免 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