2017-06-19 3 views
4

は、私はこれは私がこれまでにできる最善であるgetLineレコードフォームのリストを作成するための最短の方法は何ですか?

zones <- replicateM zoneCount $ fmap (mkZone . words) getLine 

から[String]読み取りからレコードを作成するためのshortwaysは何レコード定義

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 

があるとします。

{-# LANGUAGE NamedFieldPuns #-} 

mkZone :: [String] -> Zone 
mkZone xs = Zone {zId, zOwnerId, zPodsP0, zPodsP1, zPodsP2, zPodsP3} 
    where [zId, zOwnerId, zPodsP0, zPodsP1, zPodsP2, zPodsP3] = map read xs 

私はcodingame bot programmingsを再生するときにこれを行うには良い方法があれば、それはいいだろう、このパターンをたくさん使用しています。

答えて

8

RecordWildCardsはあなたの定型の半分を削除します。

{-# LANGUAGE RecordWildCards #-} 

mkZone :: [String] -> Zone 
mkZone xs = Zone {..} 
    where [zId, zOwnerId, zPodsP0, zPodsP1, zPodsP2, zPodsP3] = map read xs 
1

あなたはこのように、SYBでこれを行うことができます。

{-# 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 

出力:

Just (Zone {zId = 1, zOwnerId = 2, zPodsP0 = 3, zPodsP1 = 4, zPodsP2 = 5, zPodsP3 = 6}) 
Nothing 
Nothing 

あなただけのタイプのデータ(deriving Data)のインスタンスを作成する必要があります。

0

個人的には、私はRecordWildCardsに行き、それを1日と呼びます。風に注意を投げると種類を変える倍を取得するために、動的タイプを使用します。しかし、ここでこれを行うには、別の興味深いハック - しかし、方法は、いくつかの状況において有用であり得る、です!

{-# 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 -> Int -> Zone 

を:

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", "6", "7"] 
*** Exception: Type error in dynamic application. 
Can't apply function <<Zone>> to argument <<Int>> 

簡単です:

> mkZone ["1", "2", "3", "4", "5"] 
Nothing 

をしかし、あなたはあまりにも多くの引数を指定する場合は、例外を取得しますMaybe代わりに投げを返すdynApply代わりにdynAppを用いて固定しました。そして、限り、あなたは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 

をしかし、おそらくこれをしません。

関連する問題