Data.Array を使った半角カナ文字の全角文字列変換。

必要なので半角カナ文字を含む文字列を全角文字列に変換する関数を書きました。
半角文字のUCS4コードはSJISと同じ順序で並んでいますので、半角文字をそのまま配列の添え字に使って全角文字を取得しています。

まず、listArrayで半角カナ文字コードと同じ順番の全角文字リストから配列を作ります。
isHan関数で半角文字かどうか判断し、半角文字のときは zenArray ! c で全角文字に変換しています。

import Data.Array
import Data.Char
import Numeric
import Codec.Binary.UTF8.String

-- ASCIIコードの空いている部分に割り当てたときは 0xA1-0xDF。
-- UCS4 では 0xFF61-0xFF9F
-- hanKana = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚"

zenArray :: Array Char Char
zenArray = listArray (chr 0xff61,chr 0xff9f) zenKana
  where zenKana = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜"

hanSTRToZen :: String -> String
hanSTRToZen s = foldr ifHan2Zen "" s
  where 
    ifHan2Zen :: Char -> String -> String
    ifHan2Zen c acc = if isHan c then (zenArray ! c):acc else c:acc
    isHan :: Char -> Bool
    isHan c = 0xff61 <= n && n <= 0xff9f
            where n = ord c

main ::IO()
main = do 
	putStrLn $ encodeString $ hanSTRToZen "半角文字列「アイウエオカキクケコサシスセソタチツ」を変換。"

     -- > 半角文字列「アイウエオカキクケコサシスセソタチツ」を変換。

Data.Map を使って全角カナ文字を半角文字に変換。

module Main where

import qualified Data.Map as M
import Codec.Binary.UTF8.String

hanKana :: String
hanKana = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚"

zenKana :: String
zenKana = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜"

zenSTRToHan :: String -> String
zenSTRToHan s = foldr ifZen2Han "" s
  where 
    ifZen2Han :: Char -> String -> String
    ifZen2Han c acc = case M.lookup c kanaMap of
    	                Just han -> han:acc 
    	                Nothing  -> c:acc
    kanaMap :: M.Map Char Char
    kanaMap = M.fromList $ zip zenKana hanKana

main ::IO()
main = do 
	putStrLn $ encodeString $ zenSTRToHan "全角文字列「。「」、・ヲァィゥェォッーアイウ」を半角に変換。"
    -- > 全角文字列「。「」、・ヲァィゥェォッーアイウ」を半角に変換。
  • "。「」、・" はカナでないので覗くべきです。
  • 濁点、半濁点の文字は、全角から半角に変換するときは一文字から二文字に、その逆のときは二文字から一文字に変換する必要があります。

半角カナから全角カナへの変換(濁点、半濁点に対応)

{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE CPP #-}

import Foreign.Ptr
import Foreign.C.String
import Foreign.C.Types
import Foreign.Marshal.Alloc
import Data.Array

#define CP_ACP 0

utf16ToShiftJis :: String -> IO String
utf16ToShiftJis string = do
    cstring <- withCWString string bstrToCString
    str     <- peekCString cstring
    free cstring
    return str
  where
    bstrToCString :: Ptr CWchar -> IO CString
    bstrToCString bstr = do
        out_size <- cWideCharToMultiByte CP_ACP 0 bstr (-1) nullPtr 0 nullPtr nullPtr
        cstring  <- mallocBytes ((fromIntegral out_size) + 1):: IO (Ptr CChar)
        _        <- cWideCharToMultiByte CP_ACP 0 bstr (-1) cstring out_size nullPtr nullPtr
        return cstring
-- http://msdn.microsoft.com/ja-jp/library/cc448089.aspx
foreign import stdcall "windows.h WideCharToMultiByte" cWideCharToMultiByte
        :: CUInt      ->  --  UINT CodePage,           // コードページ
           CULong     ->  --  DWORD dwFlags,           // 処理速度とマッピング方法を決定するフラグ
           Ptr CWchar ->  --  LPCWSTR lpWideCharStr,   // ワイド文字列のアドレス
           CInt       ->  --  int cchWideChar,         // ワイド文字列の文字数
           CString    ->  --  LPSTR lpMultiByteStr,    // 新しい文字列を受け取るバッファのアドレス
           CInt       ->  --  int cchMultiByte,        // 新しい文字列を受け取るバッファのサイズ
           CString    ->  --  LPCSTR lpDefaultChar,    // マップできない文字の既定値のアドレス
           Ptr Int    ->  --  LPBOOL lpUsedDefaultChar //既定の文字を使ったときにセットするフラグのアドレス
           IO CInt

-- ASCIIコードの空いている部分に割り当てたときは 0xA1-0xDF。
-- UCS4 では 0xFF61-0xFF9F
-- hanKana = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚"

hanSTRToZen :: String -> String
hanSTRToZen s = hanSTRToZen' s ""

hanSTRToZen' :: String -> String -> String
hanSTRToZen' ""     acc = reverse acc
hanSTRToZen' (x:xs) acc = 
  if isHan x then case xs of
                    ""       -> hanSTRToZen' xs ((zenArray   ! x):acc)
                    ('゙':cs) -> if isDakuten x then hanSTRToZen' cs ((dakuArray  ! x):acc)
                                               else hanSTRToZen' cs ('゛':(zenArray   ! x):acc)
                    ('゚':cs) -> if isHanDaku x then hanSTRToZen' cs ((handakuAry ! x):acc)
                                               else hanSTRToZen' cs ('゜':(zenArray   ! x):acc)
                    _        -> hanSTRToZen' xs ((zenArray   ! x):acc)
  	         else hanSTRToZen' xs (x:acc)
  where
    isHan :: Char -> Bool
    isHan c = '。' <= c && c <= '゚'
    isDakuten :: Char -> Bool
    isDakuten c = ('カ' <= c && c <= 'ト') || ('ハ' <= c && c <= 'ホ')
    isHanDaku :: Char -> Bool
    isHanDaku c = 'ハ' <= c && c <= 'ホ'

zenArray :: Array Char Char
zenArray = listArray ('。','゚') zenKana
  where zenKana = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜"

dakuArray :: Array Char Char
dakuArray = listArray ('カ','ホ') dakuten
  where dakuten = "ガギグゲゴザジズゼゾダデヅデドナニヌネノバビブベボ"

handakuAry :: Array Char Char
handakuAry = listArray ('ハ','ホ') handaku
  where handaku = "パピプペポ"

main ::IO()
main = do 
    putStrLn =<< utf16ToShiftJis "文字列"
    putStrLn =<< utf16ToShiftJis (hanSTRToZen "半角文字列「ガギグゲゴザジズゼゾダヂヅデド」を変換。")
    putStrLn =<< utf16ToShiftJis (hanSTRToZen "半角文字列「バビブベボマミムメモ」を変換。")
    putStrLn =<< utf16ToShiftJis (hanSTRToZen "半角文字列「パピプペポマミムメモ」を変換。")
    putStrLn =<< utf16ToShiftJis (hanSTRToZen "濁点、半濁点の誤用「ア゙イ゙ウエオカキクケコサシ゚ス゚セソタチツ」を変換。")

    -- $ ghc --make -Wall han2zen.hs
    -- $ ./han2zen
    -- 文字列
    -- 半角文字列「ガギグゲゴザジズゼゾダデヅデド」を変換。
    -- 半角文字列「バビブベボマミムメモ」を変換。
    -- 半角文字列「パピプペポマミムメモ」を変換。
    -- 濁点、半濁点の誤用「ア゛イ゛ウエオカキクケコサシ゜ス゜セソタチツ」を変換。

参考

全角カナから半角カナへの変換(濁点、半濁点に対応)

module Main where

import qualified Data.Map as M
import Codec.Binary.UTF8.String

hanKana :: String
hanKana = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚"

zenKana :: String
zenKana = "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜"


dakuMap :: M.Map Char (Char,Char)
dakuMap = M.fromList $ zip "ガギグゲゴザジズゼゾダデヅデドバビブベボパピプペポ"
                           ((zip "カキクケコサシスセソタチツテトハヒフヘホ" (repeat '゙')) ++
                            (zip "ハヒフヘホ" (repeat '゚')))

zenSTRToHan :: String -> String
zenSTRToHan s = foldr ifZen2Han "" s
  where 
    ifZen2Han :: Char -> String -> String
    ifZen2Han c acc = case M.lookup c kanaMap of
    	                Just han -> han:acc 
    	                Nothing  -> case M.lookup c dakuMap of
    	                              Just (c1,c2) -> (c1:c2:acc)
    	                              Nothing      -> c:acc
    kanaMap :: M.Map Char Char
    kanaMap = M.fromList $ zip zenKana hanKana

main ::IO()
main = do 
	putStrLn $ encodeString $ zenSTRToHan "全角文字列「。「」、・ヲァィゥェォッーアイウ」を半角に変換。"
	putStrLn $ encodeString $ zenSTRToHan "全角文字列ガギグゲゴザジズゼゾダデヅデドバビブベボパピプペポに変換。"

    -- 全角文字列「。「」、・ヲァィゥェォッーアイウ」を半角に変換。
    -- 全角文字列ガギグゲゴザジズゼゾダデヅデドバビブベボパピプペポに変換。