假设我有记录定义
Insert INTO tableName select t1.student_Id, t1.student_name,1 from tablename t1
where t1.version = 0 and not exists
(select 1 from tablename t2 where t2.student_id = t.student_id and t2.version = 1);
从data Zone = Zone
{ zId :: Int -- this zone's ID
, zOwnerId :: Int -- the player who owns this zone (-1 otherwise)
, zPodsP0 :: Int -- player 0's PODs on this zone
, zPodsP1 :: Int -- player 1's PODs on this zone
, zPodsP2 :: Int -- player 2's PODs on this zone (always 0 for a two player game)
, zPodsP3 :: Int -- player 3's PODs on this zone (always 0 for a two or three player game)
} deriving Show
读取[String]
getLine
这是迄今为止我能做的最好的事情。
zones <- replicateM zoneCount $ fmap (mkZone . words) getLine
在播放编码bot programmings时我经常使用这种模式,如果有更好的方法可以做到这一点会很好。
答案 0 :(得分:8)
RecordWildCards
删除了一半的样板。
{-# LANGUAGE RecordWildCards #-}
mkZone :: [String] -> Zone
mkZone xs = Zone {..}
where [zId, zOwnerId, zPodsP0, zPodsP1, zPodsP2, zPodsP3] = map read xs
答案 1 :(得分:1)
You can do this with SYB, like this:
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ScopedTypeVariables #-}
import Data.Data
import Control.Monad.State
data Zone = Zone { zId, zOwnerId, zPodsP0, zPodsP1, zPodsP2, zPodsP3 :: Int }
deriving (Show, Data)
main = do
print (mygread ["1", "2", "3", "4", "5", "6"] :: Maybe Zone)
print (mygread ["a", "2", "3", "4", "5", "6"] :: Maybe Zone)
print (mygread ["1", "2", "3", "4", "5"] :: Maybe Zone)
mygread :: forall a . Data a => [String] -> Maybe a
mygread = evalStateT (fromConstrM read' constr)
where
constr = head . dataTypeConstrs . dataTypeOf $ (undefined :: a)
read' :: forall a . Data a => StateT [String] Maybe a
read' = do
x:xs <- get
put xs
lift . fmap fromConstr . readConstr (dataTypeOf (undefined :: a)) $ x
Output:
Just (Zone {zId = 1, zOwnerId = 2, zPodsP0 = 3, zPodsP1 = 4, zPodsP2 = 5, zPodsP3 = 6})
Nothing
Nothing
You only need to make your type an instance of Data (deriving Data
).
答案 2 :(得分:0)
就个人而言,我会去RecordWildCards
并称之为一天。但是这里有另一种讨厌而又有趣的方法,在某些情况下可能会有用:谨慎对待风,并使用动态类型来获得改变类型的折叠!
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Dynamic (dynApp, fromDynamic, toDyn)
import Data.List (foldl')
import Data.Typeable (Typeable)
-- Add the 'Typeable' instance to enable runtime type information.
data Zone = Zone
{ zId, zOwnerId, zPodsP0, zPodsP1, zPodsP2, zPodsP3 :: Int
} deriving (Show, Typeable)
mkZone :: [String] -> Maybe Zone
mkZone = fromDynamic . foldl' dynApp (toDyn Zone) . map (toDyn . readInt)
where
-- This type-specialised 'read' avoids an ambiguous type.
readInt :: String -> Int
readInt = read
这从Zone
构造函数开始,类型为:
Int -> Int -> Int -> Int -> Int -> Int -> Zone
然后将其连续应用于输入中的每个Int
读取,更改其类型:
Int -> Int -> Int -> Int -> Int -> Zone
Int -> Int -> Int -> Int -> Zone
Int -> Int -> Int -> Zone
Int -> Int -> Zone
Int -> Zone
Zone
它有效:
> mkZone ["1", "2", "3", "4", "5", "6"]
Just (Zone {zId = 1, zOwnerId = 2, zPodsP0 = 3, zPodsP1 = 4, zPodsP2 = 5, zPodsP3 = 6})
如果提供的参数太少,则会得到Nothing
,因为运行时强制转换失败:
> mkZone ["1", "2", "3", "4", "5"]
Nothing
但是,如果您提供许多参数,则会出现例外情况:
> mkZone ["1", "2", "3", "4", "5", "6", "7"]
*** Exception: Type error in dynamic application.
Can't apply function <<Zone>> to argument <<Int>>
使用dynApply
代替dynApp
可以很容易地修复它,它会返回Maybe
而不是投掷。只要你在Maybe
工作,你也可以使用Text.Read.readMaybe
来处理解析错误:
{-# LANGUAGE DeriveDataTypeable #-}
import Control.Monad ((<=<))
import Data.Dynamic (Dynamic, dynApply, fromDynamic, toDyn)
import Data.List (foldl')
import Data.Typeable (Typeable)
import Text.Read (readMaybe)
data Zone = Zone { … } deriving (Show, Typeable)
mkZone :: [String] -> Maybe Zone
mkZone = fromDynamic <=< foldl' go (Just (toDyn Zone)) . map readInt
where
go :: Maybe Dynamic -> Maybe Int -> Maybe Dynamic
go mAcc mx = do
acc <- mAcc
x <- mx
dynApply acc $ toDyn x
readInt :: String -> Maybe Int
readInt = readMaybe
但实际上,可能不会这样做。