12066

[code]

    data Car = NamedCar String | NamedCarWithColorName String String
    
[/code]

上のような `data` があった時に `NamedCarWithColorNameAndEngineType String String String`
を後から追加することはできますか？


CC BY-SA 3.0
2015-06-12T18:05:53.710
11299
2015-07-24T12:49:52.760
2112
question
haskell
dataに後からdata constructorを追加できますか？


定義に手を加えないという条件であれば、できません。


CC BY-SA 3.0
2015-06-24T08:49:06.103
11675
2015-06-24T08:49:06.103
8654
11299
answer


できません。  
これはHaskellの「型」が安全に使用できることを意味します。

たとえば、NamedCar -> Stringのような型を持つ関数を作成したとします。  
この関数はNamedCarとNamedCarWithColorNameの2種類の値について定義されているはずです。  
もしも、後からNamedCarWithColorNameAndEngineTypeが追加できてしまうと、  
この関数は「失敗する可能性のある関数」となってしまいます。

多くの動的型付けオブジェクト指向言語にあるような型の柔軟性はHaskellには存在しません。  
しかし、Haskellでは「より厳密な理論を背景にした」同様のコーディングができます。  
GHCの拡張機能のExistentialQuantificationを使用します。  
質問の例ならば以下のようになります。

[code]

    {-# LANGUAGE ExistentialQuantification #-}
    
    class CarClass c where
        showCar :: c -> String
    
    data Car = forall c . CarClass c => Car c
    
    instance CarClass Car where
        showCar (Car c) = showCar c
    
    data NamedCar = NamedCar String
    
    instance CarClass NamedCar where
        showCar (NamedCar n) = n
    
    data NamedCarWithColorName = NamedCarWithColorName String String
    
    instance CarClass NamedCarWithColorName where
        showCar (NamedCarWithColorName n c) = n ++ " " ++ c
    
    data NamedCarWithColorNameAndEngineType =
        NamedCarWithColorNameAndEngineType String String String
    
    instance CarClass NamedCarWithColorNameAndEngineType where
        showCar (NamedCarWithColorNameAndEngineType n c e) =
            n ++ " " ++ c ++ " " ++ e
    
    cars :: [Car]
    cars = [
        Car (NamedCar "Lexus"),
        Car (NamedCarWithColorName "Crown" "Pink"),
        Car (NamedCarWithColorNameAndEngineType "M3" "Black" "M88/3") ]
    
    main :: IO ()
    main = mapM_ (putStrLn . showCar) cars
    
[/code]


CC BY-SA 3.0
2015-07-06T04:18:58.213
12066
2015-07-24T12:49:52.760
2015-07-24T12:49:52.760
269
269
11299
answer