2011-07-14 33 views
16

在閱讀文章"Data types a la carte" by Wouter Swierstra,我已經得到了被困在翻譯如下Haskell代碼爲斯卡拉:Parametrised數據類型

data Expr f = In (f (Expr f)) 

Expr是用於在特定的方式代表算術表達式中的數據類型表達式可以寫成如下:

data Val e = Val Int 
type IntExpr = Expr Val 

data Add e = Add e e 
type AddExpr = Expr Add 

我的問題是在實施f(這可能被認爲是在簽名構造的)在斯卡拉。

P.S.定義兩個簽名的副產物,你以後可以結合數據類型,讓Expr (Val :+: Add)類型的表達式:

data (f :+: g) e = Inl (f e) | Inr (g e) 

addExample :: Expr (Val :+: Add) 
addExample = In (Inr (Add (In (Inl (Val 118))) (In (Inl (Val 1219))))) 
+0

* n.b. * - [tag:adt]是關於「Android開發工具」,而不是代數數據類型,無論如何,應用於數據類型的首字母縮寫ADT通常表示* abstract *,而不是* algebraic *。 –

+0

有兩個問題阻礙了直接實現這一點:1)通用量化。 2)高階統一。 – Apocalisp

回答

6

也許類似

case class Expr[f[_]] (in : f [Expr[f]]) 

這是不是有用,因爲在Haskell雖然。假設你定義

case class Val[e] (v: Int) 

然後Val(3)將有一個類型的Val[Nothing],你不能Expr使用它。

scala> val e = Expr(Val(3))    
<console>:9: error: no type parameters for method apply: 
(in: f[Expr[f]])Expr[f] in object Expr exist so that it can be applied 
to arguments (Val[Nothing]) 
--- because --- 
argument expression's type is not compatible with formal parameter type; 
found : Val[Nothing] 
required: ?f[ Expr[?f] ] 
     val e = Expr(Val(3)) 

您仍可以指定類型明確

val e = Expr(Val(3):Val[Expr[Val]]) 

但是這是沒有樂趣。你當然可以定義一個正確類型的函數,並用它來代替Val。

請注意,我仍然是斯卡拉noob,也許有一個更優雅的方法。

2

我突然發現這blogpost,提供了一些關於翻譯「數據類型點菜」到斯卡拉的很好的解釋。建議的解決方案如下所示:

case class Val[E](i: Int) 
case class Add[E](left: E, right: E) 

case class Expr[F[X]](e: F[Expr[F]]) 

sealed trait Sum[F[X], G[X], E] 
case class Inl[F[X], G[X], E](l: F[E]) extends Sum[F,G,E] 
case class Inr[F[X], G[X], E](r: G[E]) extends Sum[F,G,E] 

trait Apply2Of3[F[A[_],B[_],_],A[_],B[_]] { 
     type It[C] = F[A,B,C] 
} 

type Tmp[X] = Apply2Of3[Sum,Val,Add]#It[X] 

val addExample: Expr[Tmp] = In[Tmp](Inr(Add(In[Tmp](Inl(Val(118))), In[Tmp](Inl(Val(1219)))))) 

這是遠遠不甜如原來的(在Haskell製造),但在這個意義上非常有用:1)它表明這是通常​​可以實現在斯卡拉的想法,2)與Haskell相比,Scala帶來了一些弱點。