2013-02-13 75 views
3

我在Coursera的AI Planning課程中爲Haskell編程的AI常規問題解決程序,ghci抱怨模糊的類型變量。這裏是Haskell代碼和我得到的錯誤:在Haskell中編寫AI Solver時模糊的類型變量

-- Solver.hs 
{-# LANGUAGE GADTs,FlexibleInstances,UndecidableInstances,ScopedTypeVariables,TypeFamilies,MultiParamTypeClasses #-} 

module Solver 
(Solver,State,Transition) 
where 

class (Show t,Eq t) => Transition t where 
transition :: State s => s -> t -> s 

class (Show s,Eq s) => State s where 
getPossibleTransitions :: Transition t => s -> [t] 
isStateValid :: s -> Bool 
isGoalState :: s -> Bool 

class Solver s t where 
getPossibleNextStates :: s -> [s] 
isStateVisited :: [s] -> s -> Bool 
getNextFringeStates :: [s] -> [[s]] 
--getNextGeneration :: [s] -> [s] -> [s] 

flatten :: [[a]] -> [a] 
flatten [] = [] 
flatten listOfLists = (head listOfLists) ++ (flatten (tail listOfLists)) 

instance (State s,Transition t) => Solver s t where 

getPossibleNextStates (state::s) = 
    filter isStateValid (map transitionFunction possibleTransitions) 
    where 
    transitionFunction = (transition state)::(t -> s) 
    possibleTransitions = (getPossibleTransitions state)::([t]) 

isStateVisited visitedStates state = 
    any (== state) visitedStates 

getNextFringeStates (states::[s]) = 
    map (getPossibleNextStates :: (s -> [s])) (states::[s]) 

-- COMPILATION: 
{- 
Prelude> :l Solver.hs 
[1 of 1] Compiling Solver   (Solver.hs, interpreted) 

Solver.hs:38:8: 
    Ambiguous type variable `t0' in the constraint: 
     (Transition t0) arising from a use of `getPossibleNextStates' 
    Probable fix: add a type signature that fixes these type variable(s) 
    In the first argument of `map', namely 
     `(getPossibleNextStates :: s -> [s])' 
    In the expression: 
     map (getPossibleNextStates :: s -> [s]) (states :: [s]) 
    In an equation for `getNextFringeStates': 
     getNextFringeStates (states :: [s]) 
      = map (getPossibleNextStates :: s -> [s]) (states :: [s]) 
Failed, modules loaded: none. 
-} 
+0

我無法弄清楚任。 (但僅供參考,你的'flatten'函數實際上等同於Prelude中的'concat') – 2013-02-13 10:36:42

+0

你有一個用於類求解器的類型變量t,但它並沒有用到。也許你可以刪除它,看看會發生什麼。順便說一句,你真的需要ScopedTypeVariables的東西嗎? – Ingo 2013-02-13 11:12:36

回答

1

Eric Kow通過使用函數依賴來解決我的問題。他繼續按照我的要求使用類型類。這裏是他的解決方案,編譯像一個魅力:

http://pastebin.com/tnqW2QGn

這是我們的地方,我們找到了解決辦法哈斯克爾Facebook羣:

https://www.facebook.com/groups/programming.haskell/

-- Solver.hs 
{-# LANGUAGE FunctionalDependencies #-} 
{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE ScopedTypeVariables #-} 

module Solver 
    (Solver,State,Transition) 
    where 

class (Show t,Eq t) => Transition t where 
    transition :: State s => s -> t -> s 

class (Show s,Eq s) => State s where 
    getPossibleTransitions :: Transition t => s -> [t] 
    isStateValid :: s -> Bool 
    isGoalState :: s -> Bool 

class (State s, Transition t) => Solver s t | s -> t where 

    getPossibleNextStates :: s -> [s] 
    getPossibleNextStates state = 
     filter isStateValid (map transitionFunction possibleTransitions) 
     where 
     transitionFunction = transition state :: t -> s 
     possibleTransitions = getPossibleTransitions state 

    isStateVisited  :: [s] -> s -> Bool 
    isStateVisited visitedStates state = 
     any (== state) visitedStates 

    getNextFringeStates :: [s] -> [[s]] 
    getNextFringeStates = map getPossibleNextStates 
+2

「有助於診斷的type-class-it的symtpom是需要不斷引入新的語言功能以使其工作。」 – 2013-02-13 12:54:52

+0

@ChrisTaylor是的,但他真正需要的兩個人很常見。順便說一下,當我們需要像'ScopedTypeVariables'這樣的東西時,GHC會提醒我們,但是稍後不要使用它? – Ingo 2013-02-13 13:24:58

+0

@Ingo默認情況下,它不顯示警告。可能有選擇這樣做。 – 2013-02-14 08:00:50

14

我想你有一個type-class-itis的實例。也就是說,太多的類型類沒有真正做到什麼,導致複雜的代碼難以推理。

有助於診斷它的type-class-itis的symtpom是需要不斷引入新的語言功能來使東西工作。如果你繼續沿着這條路線走下去,那麼稍後你會發現自己需要編寫大量實際上並不包含任何數據的「虛擬類型」,並且只是爲了讓它們成爲各種類型類的實例而存在。

你可以閱讀更多關於類型類炎在盧克 - 帕爾默和加布裏埃爾·岡薩雷斯這些博客文章(該LP一個較爲適中,GG一個更多...極端)

更好的解決方案是要記住,功能是數據量太大。您可以將您需要的功能合併到記錄中,然後傳遞記錄。例如,你的情況我可能構建這樣的:我不

module Solver where 

data State s t = State { state :: s 
         , getPossibleTransitions :: [t] 
         , isValid :: Bool 
         , isGoal :: Bool 
         , transition :: t -> State s t } 

getPossibleNextStates :: State s t -> [State s t] 
getPossibleNextStates s = filter isValid (map transitionFunction possibleTransitions) 
    where 
     transitionFunction = transition s 
     possibleTransitions = getPossibleTransitions s 

isStateVisited :: Eq s => [s] -> State s t -> Bool 
isStateVisited visitedStates s = any (== state s) visitedStates 

getNextFringeStates :: [State s t] -> [[State s t]] 
getNextFringeStates states = map getPossibleNextStates states 

注意如何不需要引進任何特殊的語言特徵和代碼是短了很多,以及 - 19線相到38行,即使我包含了所有類型的簽名。

祝你好運!

+1

很好的答案。我經常看到的代碼試圖強制彎曲haskell到程序員經驗豐富的OO命令。唯一的影響是不必要的複雜代碼和特定擴展的濫用。 – 2013-02-13 13:41:49

+0

我繼續爲我的博客帖子提供免責聲明,以便讓人們知道我不再像以前那樣反對使用類型類的武裝。 – 2013-02-13 14:34:10

+0

@GabrielGonzalez當我說「極端」時,我並不認爲它是一種批評。我始終認爲,在那篇文章中你不是100%認真的 - 你儘可能地推動它來表達一個觀點! – 2013-02-13 14:41:54

相關問題