Haskell类型转换?

Haskell类型转换?,haskell,type-conversion,Haskell,Type Conversion,我正在尝试将列表“profile1”中的数据转换为名为“DataSubject”的自定义类型 我正在将其传递给函数“makeDS”以尝试此转换-但是以下操作不起作用: type Name = String type Age = Int type Iq = Int type Language = String data DataSubject = DS {name :: Name, age :: Age, iq :: Iq, language :: Language} deriving (S

我正在尝试将列表“profile1”中的数据转换为名为“DataSubject”的自定义类型

我正在将其传递给函数“makeDS”以尝试此转换-但是以下操作不起作用:

type Name = String 
type Age = Int 
type Iq = Int
type Language = String 
data DataSubject = DS {name :: Name, age :: Age, iq :: Iq, language :: Language} deriving (Show)
data Contain = Name String | Age Int | Iq Int | Language String deriving (Show) --Use so list can take multiple types

profile1 = [Name "Bob", Age 22, Iq 100, Language "French"]

makeDS :: [Contain] -> DataSubject
makeDS t = DS {name = t!!0, age = t!!1, iq = t!!2, language = t!!3}

main = do
  let x = makeDS profile1
  putStrLn $ show x
错误:

Couldn't match type ‘Contain’ with ‘[Char]’
我刚刚开始与哈斯克尔-谁能建议我的错误?如果有更好的方法可以做到这一点?

您的类型不匹配。您有一个包含的列表。所以当你使用

t !! 0
您得到的是一个Contain,而不是字符串,这是DS中name所必需的。您需要一个包含->名称的函数,例如

但是,这是一个局部函数,因为containToName Age 12将导致错误

请注意,这与类型类无关。现在,如果您想使用profile1,一种方法是只使用

profile1 :: DataSubject
而不是

profile1 :: [Contain]
e、 g

毕竟,[Contain]类型中没有任何东西可以确保您拥有完整数据主体的所有成分

如果有更好的方法

这取决于你想做什么。如果您只想处理DataSubject,请不要使用包含的临时列表。如果您想要处理用户输入或类似的内容,那么它会变得有点棘手。

DataSubject的声明说,我们需要为Name字段指定一个名称。名称与字符串相同。所以在表达式DS{name=t!!0,…}中,我们需要t!!0返回一个字符串。然而,t!!0返回t的元素,t的类型为[Contain]。所以不要!!0的类型为Contain,与字符串不同

要修复此类型错误,您需要将Contain转换为字符串,可能是这样:

DS { name = case t !! 0 of Name s => s, ... }
在makeDS的定义中,变量t的类型为[Contain],即Contain的列表,因此当您说t!!0这将提取该列表的第一个元素,其类型为Contain。问题是DataSubject的name字段包含一个字符串,该字符串是[Char]的别名。因此,您试图将Contain存储在[Char]的位置,这是不可能的,因为类型不同。您需要在代码中使用不同的方法

一个问题是,每个包含值都表示DataSubject的一个字段。因此,如果给我们一个包含列表,就不能保证这些值是按特定顺序给出的,例如,首先是名称,然后是年龄等,甚至不能保证所有字段都是提供的。即使您总是按照惯例在代码中以特定顺序提供所有字段,haskell也不可能知道这一点。一种不依赖于顺序的解决方案是尝试逐步构建DataSubject对象,从空DataSubject开始,然后检查包含列表并添加相应的DataSubject字段:


因此,在这里,我定义了emptyDS,它是一个空的DataSubject对象和一个名为updateDS的函数,它接受一个Contain和一个DataSubject,并根据Contain指定的字段更新DataSubject,然后返回它。最后,我使用一个fold来重复运行,使用updated从emptyDS开始更新DataSubject。

这样一个函数的目的是什么?任何可以生成[Contain]的东西都可以轻松地创建一个数据主体。你能简单地解释一下你的代码和它的具体功能吗?那么我可以接受答案我已经更新了我的答案,简单地解释了折叠的工作原理。
profile1 :: DataSubject 
profile1 = DS "Bob" 22 100 "French"
DS { name = case t !! 0 of Name s => s, ... }
makeDS :: [Contain] -> DataSubject
makeDS = foldr updateDS emptyDS
  where
    updateDS (Name s) ds = ds {name = s}
    updateDS (Age n) ds = ds {age = n}
    updateDS (Iq n) ds = ds {iq = n}
    updateDS (Language s) ds = ds {language = s}
    emptyDS = DS {name = "", age = 0, iq = 0, language = ""}