2016-01-13 40 views
1

比方說,我的應用程序有兩種類型的錯誤:Haskell的數據構造W/Scala的子類比較

λ: data AppError = FailedLogin | InvalidMessage deriving Show 

loginsendMessage功能:

λ: let login user pw = Left FailedLogin :: Either AppError String 
λ: let sendMessage msg token = Left InvalidMessage :: Either AppError Int 
λ: login "foo" "bar" >>= (\token -> sendMessage "hello world" token) 
Left FailedLogin 

但是,請注意,返回類型是Either AppError String。我不能指定Either FailedLogin ...

λ: let f = Left FailedLogin :: Either FailedLogin String 

<interactive>:18:36: 
    Not in scope: type constructor or class ‘FailedLogin’ 
    A data constructor of that name is in scope; did you mean DataKinds? 

什麼是對這種現象的原因,即不能在EitherLeft類型使用數據構建器?

其次,讓我們說,我複製上面的代碼中斯卡拉:

scala> sealed trait AppError 
defined trait AppError 

scala> case object FailedLogin extends AppError 
defined object FailedLogin 

scala> case object InvalidMessage extends AppError 
defined object InvalidMessage               

scala> def login(user: String, password: String): Either[FailedLogin.type, String] = ??? 
login: (user: String, password: String)Either[FailedLogin.type,String] 

注意,我可以指定FailedLogin作爲返回類型。如果我需要撥打電話:login >>= sendMessage,這是沒有意義的。但是,如果我只預期在EitherLeft單個值,將使用case object是慣用?還是值得創建一個帶有單個子類的sealed trait ...,引用Either的左邊的特徵?

+4

錯誤位於'::'的右側; 'FailedLogin ...'混合了兩種不同的東西 - 'Either'(一個類型構造函數)和'FailedLogin'(數據構造函數),你需要一些'類型構造函數',在這種情況下是'AppError'。注意'AppError'和'FailedLogin'存在於不同的命名空間中! – epsilonhalbe

+5

我認爲這裏的關鍵區別可以概括如下。Scala具有子類型(來自OOP傳統),像大多數FP語言一樣,Haskell沒有子類型。這就是爲什麼Scala能夠將'FailedLogin.type'作爲一個類型,它是'AppError'的一個子類型。相反,Haskell沒有這種類型,只有'AppError'類型的_value_'FailedLogin'。 – chi

回答

2

簡而言之:eaEither e a都需要是類型。在需要類型的地方使用值。 類型FailedLoginAppError。其中AppError構造函數FailedLogin

構造函數是創建某種類型值的方法。因此,對於任何數據類型data X = A | B | C ... Z,我們可以使用其任何構造函數來創建類型爲X的值。

例如,Maybe a是一種類型和Just是它的構造之一:

> :t Just 1 
Just 1 :: Num a => Maybe a 

Nothing也是Maybe的構造函數之一。

> :t Nothing 
Nothing :: Maybe a 

類型總是在數據類型的左側和構造在右邊的東西。

我不能說在斯卡拉如何.type的作品,但我要說的卻是和類型的斯卡拉的正確用法是隻在AppError而不是FailedLogin方面講。如果FailedLogin真正站立,它應該是它自己的特徵。

+1

使用「構造函數」有點不明確,因爲AppError也是一個(類型)構造函數。 「你正在使用一個_value_,你需要一個類型」可能會更清晰。 – Sarah

+0

謝謝。編輯。 – LuxuryMode