这是合法使用"未定义"还是有更好的方法?

rai*_*hoo 3 mysql haskell

我最近一直在玩MySQL-Simple.试图为该库提供一些全面的例子.我想将ID与我想要存储的实际记录分开.要为此Entity数据类型实现QueryResults的错误情况,我需要此数据类型实际使用的字段数量.因此我介绍了一个Arity类型类(很容易出错,特别是在数据发生变化时).我也在undefined这里用来调用方法的正确实例arity.

我在几个例子中看过这样的东西,但我对undefined这里的使用感到不安.有没有更好的方法来做到这一点?

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE BangPatterns #-}
module Main where

import Database.MySQL.Simple
import Database.MySQL.Simple.QueryResults
import Database.MySQL.Simple.QueryParams
import Database.MySQL.Simple.Result
import Database.MySQL.Simple.Param

connectInfo :: ConnectInfo
connectInfo = defaultConnectInfo { connectUser = "dbuser" }

data Person = Person { personName :: String
                     , personAge  :: Int
                     } deriving Show

class Arity a where
  arity :: a -> Int

instance Arity Person where
  arity _ = 2

instance QueryResults Person where
  convertResults [fname, fage] [vname, vage] =
    Person name age
      where
        !name = convert fname vname
        !age  = convert fage vage

  convertResults fs vs = convertError fs vs 2

instance QueryParams Person where
  renderParams (Person name age) = [render name, render age]

data Entity a = Entity Int a

instance (Arity a, QueryResults a) => QueryResults (Entity a) where
  convertResults (fid:fs) (vid:vs) =
    Entity id value
      where
        !id    = convert fid vid
        !value = convertResults fs vs

  convertResults fs vs =
    convertError fs vs (1 + arity (undefined :: Person))
Run Code Online (Sandbox Code Playgroud)

亲切的问候,raichoo

Cac*_*tus 7

如果arity应该只依赖于它的选择a,即它的类型,你应该使用基本上带有幻像类型标记的代理():

class Arity a where
    arity :: proxy a -> Int
Run Code Online (Sandbox Code Playgroud)

这样,实例Arity被迫不会尝试查看传递的值,而客户端不需要传递底部:

instance Arity Person where
    arity _ = 2

convertResults fs vs =
  convertError fs vs (1 + arity (Proxy :: Proxy Person))
Run Code Online (Sandbox Code Playgroud)

  • 注意如何在`arity`类型中使用`proxy a`而不是`Proxy a`,我们允许客户端使用代理的任何表示(即使是'Nothing :: Maybe Person`也可以工作),但参数仍然可以确保`arity`覆盖不能使用更多信息而不仅仅是类型. (4认同)

chi*_*chi 5

我认为没关系.如果您想要非undefined替代方案,可以使用代理幻像类型:

data Proxy a = Proxy

class Arity a where
  arity :: Proxy a -> Int

instance Arity Person where
  arity _ = 2

convertResults fs vs =
    convertError fs vs (1 + arity (Proxy :: Proxy Person))
Run Code Online (Sandbox Code Playgroud)

  • @raichoo:容易,因为代理很丑陋!您当然不应该自己定义“代理”。使用[标准实现](http://hackage.haskell.org/package/base-4.7.0.2/docs/Data-Proxy.html),或按照仙人掌的建议编写小写的`proxy`,或者– IMO最好–完全不要将其设为函数类型,而应使用[`arity ::标记为Int`](http://hackage.haskell.org/package/tagged-0.7.3/docs/Data-Tagged.html #t:已标记)。 (2认同)