我正在開發一個非常簡單的玩具 API 來提高我的 Haskell 技能。相關的資料庫表被呼叫ingredients并具有一些欄位(id, name, category)。
我現在正試圖讓一個顯示可能重復的選擇查詢正常作業。它以一種幼稚的方式做到這一點。如果兩種成分具有相同的名稱,則可能是重復的。然而,允許具有相同名稱的成分,只是它們可能是重復的。這種約束是否沒有意義并不重要,因為它只是一個玩具專案。
基本上我想在 esqueleto 中得到以下查詢:
SELECT name FROM ingredients
GROUP BY name
HAVING count(*) > 1;
我成功創建了以下 esqueleto 代碼
getDuplicateIngredientsStmt :: SqlPersistT (LoggingT IO) [E.Value Text]
getDuplicateIngredientsStmt = E.select
$ E.from
$ \ingredients -> do
E.groupBy $ ingredients E.^. IngredientName
E.having $ (E.countRows :: SqlExpr (E.Value Int)) E.>. E.val 1
return $ ingredients E.^. IngredientName
這一切都有效并編譯,太好了。但這真的就這么簡單嗎?我主要對必須將其countRows轉換為感到沮喪,SqlExpr這真的有必要嗎?
如果我省略演員表,我會收到以下錯誤(告訴我我需要演員表)
Ambiguous type variable ‘typ0’ arising from a use of ‘countRows’
prevents the constraint ‘(Num typ0)’ from being solved.
Probable fix: use a type annotation to specify what ‘typ0’ should be.
uj5u.com熱心網友回復:
啊,你已經在使用TypeApplications擴展了。這提供了一種更簡單的方法。
E.having $ E.countRows E.>. E.val @Int 1
E.val這設定了to型別中唯一的自由型別變數Int,它可以滿足您的所有需求。
至于為什么有必要,那是因為 的型別E.val和E.>.引入了一個PersistField約束,所以1最終被推斷為具有 type (PersistField t, Num t) => t。這可以防止默認設定,因為常規默認設定規則僅在約束位于編譯器知道的最小集合中時適用。(ExtendedDefaultRules擴展會導致它默認為,Integer因為它知道如何處理Num約束的一部分,但我認為這并不是你真正想要的。)
我只是對您參考的錯誤訊息沒有提到這兩個約束感到困惑。這將使缺乏違約的情況更加明顯。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/528498.html
標籤:哈斯克尔埃斯克莱托
