------------------------------------------------------------------------------- |-- Module : Text.Printf-- Copyright : (c) Lennart Augustsson, 2004-- License : BSD-style (see the file libraries/base/LICENSE)-- -- Maintainer : lennart@augustsson.net-- Stability : provisional-- Portability : portable---- A C printf like formatter.-------------------------------------------------------------------------------moduleText.Printf(printf,hPrintf,PrintfType,HPrintfType,PrintfArg,IsChar)whereimportPreludeimportData.CharimportData.IntimportData.WordimportNumeric(showEFloat,showFFloat,showGFloat)importSystem.IO--------------------- | Format a variable number of arguments with the C-style formatting string.-- The return value is either 'String' or @('IO' a)@.---- The format string consists of ordinary characters and /conversion-- specifications/, which specify how to format one of the arguments-- to printf in the output string. A conversion specification begins with the-- character @%@, followed by one or more of the following flags:---- > - left adjust (default is right adjust)-- > + always use a sign (+ or -) for signed conversions-- > 0 pad with zeroes rather than spaces---- followed optionally by a field width:-- -- > num field width-- > * as num, but taken from argument list---- followed optionally by a precision:---- > .num precision (number of decimal places)---- and finally, a format character:---- > c character Char, Int, Integer, ...-- > d decimal Char, Int, Integer, ...-- > o octal Char, Int, Integer, ...-- > x hexadecimal Char, Int, Integer, ...-- > X hexadecimal Char, Int, Integer, ...-- > u unsigned decimal Char, Int, Integer, ...-- > f floating point Float, Double-- > g general format float Float, Double-- > G general format float Float, Double-- > e exponent format float Float, Double-- > E exponent format float Float, Double-- > s string String---- Mismatch between the argument types and the format string will cause-- an exception to be thrown at runtime.---- Examples:---- > > printf "%d\n" (23::Int)-- > 23-- > > printf "%s %s\n" "Hello" "World"-- > Hello World-- > > printf "%.2f\n" pi-- > 3.14--printf::(PrintfTyper)=>String->rprintffmts=sprfmts[]-- | Similar to 'printf', except that output is via the specified-- 'Handle'. The return type is restricted to @('IO' a)@.hPrintf::(HPrintfTyper)=>Handle->String->rhPrintfhdlfmts=hsprhdlfmts[]-- |The 'PrintfType' class provides the variable argument magic for-- 'printf'. Its implementation is intentionally not visible from-- this module. If you attempt to pass an argument of a type which-- is not an instance of this class to 'printf' or 'hPrintf', then-- the compiler will report it as a missing instance of 'PrintfArg'.classPrintfTypetwherespr::String->[UPrintf]->t-- | The 'HPrintfType' class provides the variable argument magic for-- 'hPrintf'. Its implementation is intentionally not visible from-- this module.classHPrintfTypetwherehspr::Handle->String->[UPrintf]->t{- not allowed in Haskell 98instance PrintfType String where spr fmt args = uprintf fmt (reverse args)-}instance(IsCharc)=>PrintfType[c]wheresprfmtsargs=mapfromChar(uprintffmts(reverseargs))instancePrintfType(IOa)wheresprfmtsargs=doputStr(uprintffmts(reverseargs))returnundefinedinstanceHPrintfType(IOa)wherehsprhdlfmtsargs=dohPutStrhdl(uprintffmts(reverseargs))returnundefinedinstance(PrintfArga,PrintfTyper)=>PrintfType(a->r)wheresprfmtsargs=\a->sprfmts(toUPrintfa:args)instance(PrintfArga,HPrintfTyper)=>HPrintfType(a->r)wherehsprhdlfmtsargs=\a->hsprhdlfmts(toUPrintfa:args)classPrintfArgawheretoUPrintf::a->UPrintfinstancePrintfArgCharwheretoUPrintfc=UCharc{- not allowed in Haskell 98instance PrintfArg String where toUPrintf s = UString s-}instance(IsCharc)=>PrintfArg[c]wheretoUPrintf=UString.maptoCharinstancePrintfArgIntwheretoUPrintf=uIntegerinstancePrintfArgInt8wheretoUPrintf=uIntegerinstancePrintfArgInt16wheretoUPrintf=uIntegerinstancePrintfArgInt32wheretoUPrintf=uIntegerinstancePrintfArgInt64wheretoUPrintf=uInteger#ifndef__NHC__instancePrintfArgWordwheretoUPrintf=uInteger#endifinstancePrintfArgWord8wheretoUPrintf=uIntegerinstancePrintfArgWord16wheretoUPrintf=uIntegerinstancePrintfArgWord32wheretoUPrintf=uIntegerinstancePrintfArgWord64wheretoUPrintf=uIntegerinstancePrintfArgIntegerwheretoUPrintf=UInteger0instancePrintfArgFloatwheretoUPrintf=UFloatinstancePrintfArgDoublewheretoUPrintf=UDoubleuInteger::(Integrala,Boundeda)=>a->UPrintfuIntegerx=UInteger(toInteger$minBound`asTypeOf`x)(toIntegerx)classIsCharcwheretoChar::c->CharfromChar::Char->cinstanceIsCharCharwheretoCharc=cfromCharc=c-------------------dataUPrintf=UCharChar|UStringString|UIntegerIntegerInteger|UFloatFloat|UDoubleDoubleuprintf::String->[UPrintf]->Stringuprintf""[]=""uprintf""(_:_)=fmterruprintf('%':'%':cs)us='%':uprintfcsusuprintf('%':_)[]=argerruprintf('%':cs)us@(_:_)=fmtcsusuprintf(c:cs)us=c:uprintfcsusfmt::String->[UPrintf]->Stringfmtcsus=let(width,prec,ladj,zero,plus,cs',us')=getSpecsFalseFalseFalsecsusadjust(pre,str)=letlstr=lengthstrlpre=lengthprefill=iflstr+lpre<widththentake(width-(lstr+lpre))(repeat(ifzerothen'0'else' '))else""inifladjthenpre++str++fillelseifzerothenpre++fill++strelsefill++pre++stradjust'("",str)|plus=adjust("+",str)adjust'ps=adjustpsincasecs'of[]->fmterrc:cs''->caseus'of[]->argerru:us''->(casecof'c'->adjust("",[toEnum(tointu)])'d'->adjust'(fmtiu)'i'->adjust'(fmtiu)'x'->adjust("",fmtu16u)'X'->adjust("",maptoUpper$fmtu16u)'o'->adjust("",fmtu8u)'u'->adjust("",fmtu10u)'e'->adjust'(dfmt'cprecu)'E'->adjust'(dfmt'cprecu)'f'->adjust'(dfmt'cprecu)'g'->adjust'(dfmt'cprecu)'G'->adjust'(dfmt'cprecu)'s'->adjust("",tostru)_->perror("bad formatting char "++[c]))++uprintfcs''us''fmti::UPrintf->(String,String)fmti(UInteger_i)=ifi<0then("-",show(-i))else("",showi)fmti(UCharc)=fmti(uInteger(fromEnumc))fmti_=baderrfmtu::Integer->UPrintf->Stringfmtub(UIntegerli)=itosbb(ifi<0then-2*l+ielsei)fmtub(UCharc)=itosbb(toInteger(fromEnumc))fmtu__=baderrtoint::UPrintf->Inttoint(UInteger_i)=fromIntegeritoint(UCharc)=fromEnumctoint_=baderrtostr::UPrintf->Stringtostr(UStrings)=stostr_=baderritosb::Integer->Integer->Stringitosbbn=ifn<bthen[intToDigit$fromIntegern]elselet(q,r)=quotRemnbinitosbbq++[intToDigit$fromIntegerr]stoi::Int->String->(Int,String)stoia(c:cs)|isDigitc=stoi(a*10+digitToIntc)csstoiacs=(a,cs)getSpecs::Bool->Bool->Bool->String->[UPrintf]->(Int,Int,Bool,Bool,Bool,String,[UPrintf])getSpecs_zs('-':cs)us=getSpecsTruezscsusgetSpecslz_('+':cs)us=getSpecslzTruecsusgetSpecsl_s('0':cs)us=getSpecslTruescsusgetSpecslzs('*':cs)us=caseusof[]->argerrnu:us'->letn=tointnu(p,cs'',us'')=casecsof'.':'*':r->caseus'of{[]->argerr;pu:us'''->(tointpu,r,us''')}'.':r->let(n',cs')=stoi0rin(n',cs',us')_->(-1,cs,us')in(n,p,l,z,s,cs'',us'')getSpecslzs('.':cs)us=let(p,cs')=stoi0csin(0,p,l,z,s,cs',us)getSpecslzscs@(c:_)us|isDigitc=let(n,cs')=stoi0cs(p,cs'')=casecs'of'.':r->stoi0r_->(-1,cs')in(n,p,l,z,s,cs'',us)getSpecslzscsus=(0,-1,l,z,s,cs,us)dfmt'::Char->Int->UPrintf->(String,String)dfmt'cp(UDoubled)=dfmtcpddfmt'cp(UFloatf)=dfmtcpfdfmt'___=baderrdfmt::(RealFloata)=>Char->Int->a->(String,String)dfmtcpd=case(ifisUppercthenmaptoUpperelseid)$(casetoLowercof'e'->showEFloat'f'->showFFloat'g'->showGFloat_->error"Printf.dfmt: impossible")(ifp<0thenNothingelseJustp)d""of'-':cs->("-",cs)cs->("",cs)perror::String->aperrors=error("Printf.printf: "++s)fmterr,argerr,baderr::afmterr=perror"formatting string ended prematurely"argerr=perror"argument list ended prematurely"baderr=perror"bad argument"
nobsun
#4401()
[
Haskell
]
Rating-2/6=-0.33
Haskellの場合,可変長引数の扱いに工夫が必要です.
下手なコードを書くより,ghcのライブラリを読んで実際にどうしているかを見る方が勉強になると思うので,ライブラリのコード(Text.Printfモジュール)をそのまま掲載します.
Rating-2/6=-0.33-0+
[ reply ]