2011-12-08 50 views
0

我有一個函數太複雜,我不明白函數類型應該是什麼。我試圖讓GHC同意我期望的是它所期望的。首先,功能,我認爲應該做的。然後,在混淆的來源。需要幫助清理與返回類型混淆

flagScheduled ((Left (MkUFD day)):rest) = do 
    match <- runDB $ selectList [TestStartDate ==. Just day, 
           TestStatus /<-. [Passed,Failed]] [] 
    case (L.null match) of 
     True -> do 
       processedDays <- ([(Left $ MkUFD day)] :) <$> flagScheduled rest 
       return processedDays 
     False -> do 
       let flaggedRange = (calcFlagged match) 
        product  = (testFirmware . snd . P.head) match 
       processedDays <- (flagScheduled' 
            ([(Left $ MkUFD day)] ++ 
            (L.take flaggedRange) rest) (show product) :) <$> 
            (flagScheduled . L.drop flaggedRange) rest 
       return processedDays 
flagScheduled ((Right day):rest) = do 
    processedDays <- ((Right $ day):) <$> flagScheduled rest 
    return processedDays 
flagScheduled _ = return [] 

calcFlagged ((_ ,(Test _ _ (Just startDate) (Just endDate) _ _)) : rest) = 
    fromIntegral $ C.diffDays endDate startDate 

flagScheduled' toBeFlagged product = 
    L.map (flagIt product) toBeFlagged 
    where flagIt product (Left (MkUFD day)) = Right $ 
               MkCal $ 
               Right $ 
               MkUAD $ 
               Left $ 
               MkSDay day 
                 (read product :: Product) 
                 Reserved 

的想法是我先說一個[Either UnFlaggedDay CalendarDay] 我通過列表轉換一些UnFlaggedDay S的進CalendarDay小號迭代。 其他功能將改變UnFlaggedDay的其餘部分。在下面我定義我正在使用的類型。

newtype AvailableDay = MkAD (Text, C.Day) 
          deriving (Show, Eq) 

newtype UnAvailableDay = MkUAD (Either ScheduledDay Out_Of_Office) 
          deriving Show 

data ScheduledDay = MkSDay C.Day Product ScheduledState 
         deriving Show 

newtype ReservedDay = MkRDay (C.Day,Product) 
           deriving (Ord,Show,Eq,Read) 

newtype ASAPDay = MkADay (C.Day,Product) 
          deriving (Ord,Show,Eq,Read) 

newtype UnFlaggedDay = MkUFD C.Day 

newtype CalendarDay = MkCal (Either AvailableDay UnAvailableDay) 
           deriving Show 

所以這裏是問題,當我編譯我得到這個錯誤,這本身並不令人困惑。

Utils/BuildDateList.hs:173:44: 
     Couldn't match expected type `Either a0 b0' 
        with actual type `[Either UnFlaggedDay CalendarDay]' 
     Expected type: GGHandler sub0 master0 monad0 [Either a0 b0] 
      Actual type: GGHandler 
         sub0 master0 monad0 [[Either UnFlaggedDay CalendarDay]] 
     In the return type of a call of `flagScheduled' 
     In the second argument of `(<$>)', namely `flagScheduled rest' 

好細,它看起來像我需要做的就是申請一個精心佈置的CONCAT,我可以做的實際類型GGHandler sub0 master0 monad0 [[Either UnFlaggedDay CalendarDay]] 符合預期的類型GGHandler sub0 master0 monad0 [[Either UnFlaggedDay CalendarDay]]

別急,沒那麼簡單。這是很多人的嘗試,無論我在哪裏放置concat,它似乎都會導致相同的錯誤。

Utils/BuildDateList.hs:164:16: 
     Couldn't match expected type `[Either UnFlaggedDay b0]' 
        with actual type `Either UnFlaggedDay b0' 
     Expected type: GGHandler 
         sub0 master0 monad0 [[Either UnFlaggedDay b0]] 
     Actual type: GGHandler 
         sub0 master0 monad0 [Either UnFlaggedDay b0] 
     In the expression: return $ P.concat processedDays 
     In the expression: 
     do { processedDays <- ([(Left $ MkUFD day)] :) 
          <$> 
           flagScheduled rest; 
       return $ P.concat processedDays } 

你看到那裏發生了什麼?以下是我所做的更改。在傳遞給return之前,我通過了processedDaysconcat

flagScheduled ((Left (MkUFD day)):rest) = do 
    match <- runDB $ selectList [TestStartDate ==. Just day, 
           TestStatus /<-. [Passed,Failed]] [] 
    case (L.null match) of 
     True -> do 
       processedDays <- ([(Left $ MkUFD day)] :) <$> flagScheduled rest 
       return $ P.concat processedDays 
     False -> do 
       let flaggedRange = (calcFlagged match) 
        product  = (testFirmware . snd . P.head) match 
       processedDays <- (flagScheduled' 
            ([(Left $ MkUFD day)] ++ 
            (L.take flaggedRange) rest) (show product) :) <$> 
            (flagScheduled . L.drop flaggedRange) rest 
       return $ P.concat processedDays 
flagScheduled ((Right day):rest) = do 
    processedDays <- ((Right $ day):) <$> flagScheduled rest 
    return $ P.concat processedDays 
flagScheduled _ = return [] 

因此,看起來像是一種直截了當的變化並不是這樣的事實,表明我並不真正瞭解問題所在。有任何想法嗎?

更新:我所做的更改丹尼爾建議,但得到這個錯誤:

Utils/BuildDateList.hs:169:37: 
    Couldn't match expected type `[Either UnFlaggedDay t0]' 
       with actual type `Either UnFlaggedDay b0' 
    In the first argument of `(++)', namely `(Left $ MkUFD day)' 
    In the first argument of `flagScheduled'', namely 
     `((Left $ MkUFD day) ++ (P.take flaggedRange) rest)' 
    In the first argument of `(:)', namely 
     `flagScheduled' 
     ((Left $ MkUFD day) ++ (P.take flaggedRange) rest) (show product)' 

更新:這個問題已經解決了,只露出其他(類似)的問題。我要接受這裏給出的建議來推進。

+7

我強烈地將其分解爲幾個較短的函數 - 當情況發生變化時,它們將更容易測試,更容易維護並更容易適應。 –

+1

嘿,這是一些很好的輔助......「更容易測試/更容易維護/更容易適應環境變化!」這將成爲我的口頭禪。 –

回答

3

首先懷疑:

case (L.null match) of 
     True -> do 
      processedDays <- ([(Left $ MkUFD day)] :) <$> flagScheduled rest 
      return processedDays 

也許應該讀

case (L.null match) of 
     True -> do 
      processedDays <- ((Left $ MkUFD day) :) <$> flagScheduled rest 
      return processedDays 

?哦,並開始寫入類型簽名。這通常會產生更好的錯誤消息。

+0

我試圖寫入類型簽名。和Yesod類型一樣,我錯了。我的習慣是讓類型系統把它整理出來,因爲它幾乎總是這樣。 –

+1

@MichaelLitchard那麼混合方法呢?你從容易的部分開始,在這裏'flagScheduled((Right day):rest)= ...'。你問ghci是什麼類型,並填寫你知道如何填寫的所有類型變量。下一個等式,重複。 –

+1

您還需要更改 '((Left $ MkUFD day)++(P.(flaggedRange)rest)' to((Left $ MkUFD day):P.take flaggedRange rest) –