2016-09-12 12 views
0

'profile1'목록의 데이터를 'DataSubject'라는 사용자 지정 유형으로 변환하려고합니다.하스켈 - 타입 변환?

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]’ 

난 그냥 시작있어 다음과 같은 작동하지 않습니다하지만 -

나는이 변환을 시도하는 'makeDS'기능이 전달 해요 하스켈과 함께 - 누군가 내 오류에 대해 조언 할 수 있습니까? 그리고 이것을하는 더 좋은 방법이 있다면?

+0

이러한 기능의 목적은 무엇입니까? '[Contain]'를 생성 할 수있는 어떤 것이라도'DataSubject'를 쉽게 만들 수 있습니다. – chepner

답변

7

makeDS의 정의에서 변수 t 유형 [Contain]이다 (즉,Contain의 목록), t!!0이라고 말하면이 목록의 첫 번째 요소 인 Contain이 추출됩니다. 문제는 name 필드에 DataSubjectString (별칭은 [Char])입니다. 따라서 [Char] 대신 Contain을 저장하려고합니다. 유형이 다르기 때문에 불가능합니다. 코드에서 다른 접근 방식이 필요합니다.

모든 문제는 모든 단일 값이 DataSubject의 단일 필드를 나타냅니다. 따라서 Contain의 목록이 제공되면 값이 특정 순서 (예 : Name1, 그 다음은 Age 등)로 표시되거나 모든 입력란이 제공된다는 보장이 없습니다. 컨벤션으로 코드의 특정 순서로 항상 모든 필드를 제공하더라도 haskell은이를 알 수 없습니다.

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 = ""} 
: 순서에 의존하지 않는 하나의 해결책은 해당 DataSubject 필드를 DataSubject에 "빈"로 시작하고 Contain의 목록을 검사하고 추가하여 DataSubject 객체 단계별 "를 구축"하는 것입니다

그래서 여기에, 나는 "빈"DataSubject 객체입니다 emptyDS을 정의하고 함수는 (단일) ContainDataSubject을 가지고 Contain에 의해 지정된 필드에 따라 DataSubject를 업데이트 한 후 그것을 반환 updateDS을했다. 마지막으로 접힌 부분을 사용하여 updateDS을 사용하여 DataSubject (emptyDS으로 시작)을 반복적으로 업데이트합니다.

+0

코드에 대한 간략한 설명을 추가하고 정확하게 무엇을했는지 대답을 받아 들일 수 있습니까? –

+1

접기가 어떻게 작동하는지 간단히 설명하여 답변을 업데이트했습니다. – redneb

3

유형 불일치이 있습니다. Contain의 목록이 있습니다. 당신이

t !! 0 

를 사용할 때 그래서 당신은 DS에서 name을 위해 필요하다 Contain 아닌 String 얻을. 함수 Contain -> Name이 필요합니다. containToName (Age 12) 오류가 발생할 것이므로

containToName :: Contain -> Name 
containToName (Name xs) = xs 
containToName _   = error "not a name" 

그러나 이는 부분적인 기능이다.

과는 아무 관련이 없습니다. 당신이 profile1 사용하려면 이제 한 가지 방법은

profile1 :: DataSubject 

대신

profile1 :: [Contain] 

사용하는 것, 예를 들어 결국

profile1 :: DataSubject 
profile1 = DS "Bob" 22 100 "French" 

, 당신은 완전한 DataSubject에 대한 모든 재료를 가지고 있는지 확인합니다 유형[Contain] 아무것도 없다.

And if there's better ways of doing this?

이는 원하는 작업에 따라 다릅니다. DataSubject 초만 처리하려면 Contain 임시 목록을 사용하지 마십시오. 사용자 입력 (또는 유사)을 처리하려는 경우 조금 더 까다 롭습니다.

1

DataSubject 선언은 name 필드에 Name이 필요하다고 말합니다. NameString과 같습니다. 따라서 DS {name = t!!0, ...}이라는 표현식에서 String을 반환하려면 t !! 0이 필요합니다. 그러나 t !! 0t의 요소를 반환하고 t[Contain] 유형을 반환합니다. 그래서 t !! 0String과 다른 종류 Contain입니다.

당신은 어쩌면 그렇게하는 StringContain을 변환해야, 이러한 유형의 오류를 해결하려면 :

DS { name = case t !! 0 of Name s => s, ... }