使用 Haskell 的简单 where 子句键入错误
Type error with simple where-clause with Haskell's beam
我正在尝试使用 Haskell 的 beam 创建一个带有简单 where 子句的 select 查询。来自 https://haskell-beam.github.io/beam/user-guide/queries/select/#where-clause,我相信这会奏效:
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeSynonymInstances #-}
module Lib where
import Data.Int ( Int32 )
import Data.Word ( Word32 )
import Database.Beam
data FooT f
= Foo
{ _fooId :: Columnar f Int32
, _fooBar :: Columnar f Word32
}
deriving (Generic, Beamable)
instance Table FooT where
data PrimaryKey FooT f =
FooId (Columnar f Int32) deriving (Generic, Beamable)
primaryKey = FooId . _fooId
type Foo = FooT Identity
type FooId = PrimaryKey FooT Identity
deriving instance Show Foo
deriving instance Eq Foo
data BazDb f = BazDb
{ _bazFoos :: f (TableEntity FooT)
}
deriving (Generic, Database be)
bazDb :: DatabaseSettings be BazDb
bazDb = defaultDbSettings
selectFoosByBar :: HasQBuilder be => Word32 -> SqlSelect be Foo
selectFoosByBar bar = select $
filter_ (\foo -> _fooBar foo ==. bar) $
all_ $ _bazFoos bazDb
但是我遗漏了一些重要的细节,所以我得到以下编译错误:
<SNIP>/Lib.hs:42:22: error:
• Couldn't match type ‘QGenExpr QValueContext be QBaseScope Word32’
with ‘Word32’
Expected type: Word32
Actual type: Columnar (QExpr be QBaseScope) Word32
• In the first argument of ‘(==.)’, namely ‘_fooBar foo’
In the expression: _fooBar foo ==. bar
In the first argument of ‘filter_’, namely
‘(\ foo -> _fooBar foo ==. bar)’
• Relevant bindings include
foo :: FooT (QExpr be QBaseScope) (bound at src/Lib.hs:42:15)
selectFoosByBar :: Word32 -> SqlSelect be Foo
(bound at src/Lib.hs:41:1)
|
42 | filter_ (\foo -> _fooBar foo ==. bar) $
|
现在,错误信息本身已经很清楚了,但我不太明白 ==.
的哪一边需要修改,也不知道如何修改。或者,如果它是缺少某些扩展名或类型注释的问题。
在违规行中,bar :: Word32
(根据 selectFoosByBar
的签名)。
我觉得_fooBar foo
是一个Columnar (something) Word32
.
错误消息说问题出在 ==.
的第一个 arg,但看看 type of ==.
,我想你可以改变任何一方以获得一致意见。
为什么是bar :: Word32
?这具有直觉意义;您正在尝试按单词过滤,因此 arg 应该是一个单词。这表明您可能想对 _fooBar foo
做一些事情以从中获得 Word32
。这可能是一个简单的函数,但更有可能是相反的:以某种方式将您的 ==. bar
操作提升到“查询表达式”space.
代码的相关部分
selectFoosByBar bar = select $
filter_ (\foo -> _fooBar foo ==. bar) $
all_ $ _bazFoos bazDb
如果我们查看 ==.
,您会看到 (==.) :: SqlEq expr a => a -> a -> expr Bool
,因此 ==.
的两边需要具有相同的类型。
现在看看 (==.) 左边的内容,我们看到 _fooBar foo :: Columnar f Word32
。我们无法摆脱 Columnar,但我们可以使用 val_
:
将 bar 变成 beam 可以使用的东西
selectFoosByBar bar = select $
filter_ (\foo -> _fooBar foo ==. val_ bar) $
all_ $ _bazFoos bazDb
注意这只有在我们删除类型注释时才有效。使用类型注释,它看起来像:
selectFoosByBar
:: (HasQBuilder be, HasSqlEqualityCheck be Word32,
HasSqlValueSyntax
(Sql92ExpressionValueSyntax
(Sql92SelectTableExpressionSyntax
(Sql92SelectSelectTableSyntax
(Sql92SelectSyntax (BeamSqlBackendSyntax be)))))
Word32) =>
Word32 -> SqlSelect be (FooT Identity)
selectFoosByBar bar = select $
filter_ (\foo -> _fooBar foo ==. val_ bar) $
all_ $ _bazFoos bazDb
我认为它需要这个巨大的注释以便 ghc 可以跟踪 be
抽象出的后端。
编辑:
如果我们启用 ConstraintKinds
我们可以简化注释:
type MagicSql be =
HasSqlValueSyntax
(Sql92ExpressionValueSyntax
(Sql92SelectTableExpressionSyntax
(Sql92SelectSelectTableSyntax
(Sql92SelectSyntax (BeamSqlBackendSyntax be)))))
selectFoosByBar
:: (HasQBuilder be, HasSqlEqualityCheck be Word32, MagicSql be Word32) =>
Word32 -> SqlSelect be (FooT Identity)
我正在尝试使用 Haskell 的 beam 创建一个带有简单 where 子句的 select 查询。来自 https://haskell-beam.github.io/beam/user-guide/queries/select/#where-clause,我相信这会奏效:
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeSynonymInstances #-}
module Lib where
import Data.Int ( Int32 )
import Data.Word ( Word32 )
import Database.Beam
data FooT f
= Foo
{ _fooId :: Columnar f Int32
, _fooBar :: Columnar f Word32
}
deriving (Generic, Beamable)
instance Table FooT where
data PrimaryKey FooT f =
FooId (Columnar f Int32) deriving (Generic, Beamable)
primaryKey = FooId . _fooId
type Foo = FooT Identity
type FooId = PrimaryKey FooT Identity
deriving instance Show Foo
deriving instance Eq Foo
data BazDb f = BazDb
{ _bazFoos :: f (TableEntity FooT)
}
deriving (Generic, Database be)
bazDb :: DatabaseSettings be BazDb
bazDb = defaultDbSettings
selectFoosByBar :: HasQBuilder be => Word32 -> SqlSelect be Foo
selectFoosByBar bar = select $
filter_ (\foo -> _fooBar foo ==. bar) $
all_ $ _bazFoos bazDb
但是我遗漏了一些重要的细节,所以我得到以下编译错误:
<SNIP>/Lib.hs:42:22: error:
• Couldn't match type ‘QGenExpr QValueContext be QBaseScope Word32’
with ‘Word32’
Expected type: Word32
Actual type: Columnar (QExpr be QBaseScope) Word32
• In the first argument of ‘(==.)’, namely ‘_fooBar foo’
In the expression: _fooBar foo ==. bar
In the first argument of ‘filter_’, namely
‘(\ foo -> _fooBar foo ==. bar)’
• Relevant bindings include
foo :: FooT (QExpr be QBaseScope) (bound at src/Lib.hs:42:15)
selectFoosByBar :: Word32 -> SqlSelect be Foo
(bound at src/Lib.hs:41:1)
|
42 | filter_ (\foo -> _fooBar foo ==. bar) $
|
现在,错误信息本身已经很清楚了,但我不太明白 ==.
的哪一边需要修改,也不知道如何修改。或者,如果它是缺少某些扩展名或类型注释的问题。
在违规行中,bar :: Word32
(根据 selectFoosByBar
的签名)。
我觉得_fooBar foo
是一个Columnar (something) Word32
.
错误消息说问题出在 ==.
的第一个 arg,但看看 type of ==.
,我想你可以改变任何一方以获得一致意见。
为什么是bar :: Word32
?这具有直觉意义;您正在尝试按单词过滤,因此 arg 应该是一个单词。这表明您可能想对 _fooBar foo
做一些事情以从中获得 Word32
。这可能是一个简单的函数,但更有可能是相反的:以某种方式将您的 ==. bar
操作提升到“查询表达式”space.
代码的相关部分
selectFoosByBar bar = select $
filter_ (\foo -> _fooBar foo ==. bar) $
all_ $ _bazFoos bazDb
如果我们查看 ==.
,您会看到 (==.) :: SqlEq expr a => a -> a -> expr Bool
,因此 ==.
的两边需要具有相同的类型。
现在看看 (==.) 左边的内容,我们看到 _fooBar foo :: Columnar f Word32
。我们无法摆脱 Columnar,但我们可以使用 val_
:
selectFoosByBar bar = select $
filter_ (\foo -> _fooBar foo ==. val_ bar) $
all_ $ _bazFoos bazDb
注意这只有在我们删除类型注释时才有效。使用类型注释,它看起来像:
selectFoosByBar
:: (HasQBuilder be, HasSqlEqualityCheck be Word32,
HasSqlValueSyntax
(Sql92ExpressionValueSyntax
(Sql92SelectTableExpressionSyntax
(Sql92SelectSelectTableSyntax
(Sql92SelectSyntax (BeamSqlBackendSyntax be)))))
Word32) =>
Word32 -> SqlSelect be (FooT Identity)
selectFoosByBar bar = select $
filter_ (\foo -> _fooBar foo ==. val_ bar) $
all_ $ _bazFoos bazDb
我认为它需要这个巨大的注释以便 ghc 可以跟踪 be
抽象出的后端。
编辑:
如果我们启用 ConstraintKinds
我们可以简化注释:
type MagicSql be =
HasSqlValueSyntax
(Sql92ExpressionValueSyntax
(Sql92SelectTableExpressionSyntax
(Sql92SelectSelectTableSyntax
(Sql92SelectSyntax (BeamSqlBackendSyntax be)))))
selectFoosByBar
:: (HasQBuilder be, HasSqlEqualityCheck be Word32, MagicSql be Word32) =>
Word32 -> SqlSelect be (FooT Identity)