값이 제약 조건을 충족한다는 것을 유형으로 보장

URL을 나타내는 문자열이거나, 0 이상인 것이 요구되는 정수이든, 값이 어떠한 제약을 만족할 것을 요구되는 장면은 많이 있습니다.

예를 들어, 남녀 2마리의 염소씨의 뿔의 개수를 인수에 있어서, 그 2마리의 염소씨가 사랑하고 교미해 아이를 만들어도 문제가 없는지를 판단하는 함수를 정의합니다.
canMakeLove : Int -> Int -> Bool

각각의 모퉁이의 수를 인수에 있어 Bool형을 돌려주는 자연스러운 설계군요?

하지만 잠시 기다려주세요!
유각 염소는 2개밖에 모퉁이가 없습니다.
따라서 염소 씨의 취할 수 있는 모서리의 수는 다음 중 하나밖에 있을 수 없을 것입니다.
  • 0 개 : 태어난 무각의 염소 씨 또는 유각의 염소 짱의 싹을 구워서 구운 (단말마와 같은 비명이 난다)
  • 1개: 유각의 염소 짱의 싹을 태웠지만 불충분하고 1개만 남았다(단말마의 비명이 낭비되었다 😱)
  • 2개: 태어난 유각
  • 3 개 이상 : 염색체에 이상이 있으므로 여기에서는 염소로 간주되지 않습니다

  • 즉, canMakeLove 의 인수에 3 이상의 정수를 주면 동작이 보증되지 않게 되어 버립니다.

    그렇지만, 함수를 사용하는 측이 「조심해서 사용한다」란, 현대의 프로그래밍에서는 있을 수 없지요?
    제대로 기술을 사용하여 해결합시다!



    Horn형 도입



    이와 같이, 어떤 제약을 가지는 것이 값에 요구되는 장면에서 자주 사용되는 테크닉이 있습니다.
    형태에 의해 값이 제약을 가지는 것을 보증해 버립니다.

    바로 해보자!
    module Horn
        exposing
            ( Horn
            , fromInt
            , toInt
            )
    
    
    {-| 角の本数をあらわす専用の型
    -}
    type Horn =
        Horn Int
    
    
    {-| `Horn` 型の値を作成する唯一の方法
    
        fromInt 3
        --> Nothing
    
        fromInt 2
        --> Just (Horn 2)
    -}
    fromInt : Int -> Maybe Horn
    fromInt n =
        if (0 <= n && n <= 2)
            then
                Just (Horn n)
            else
                Nothing
    
    
    {-| `Horn` 型の値を整数に変換する唯一の方法
    -}
    toInt : Horn -> Int
    toInt (Horn n) = n
    
    
    
    {-| オスとメス(順不同)の角の本数から、その2頭が交尾しても問題ないかどうかどうかを判定する関数
    -}
    canMakeLove : Horn -> Horn -> Bool
    canMakeLove = ...
    

    우선 주목하고 싶은 것은 HornOpaque type 가 되어 있는 것입니다.
    module Horn
        exposing
            ( Horn(..)
            , ...
    

    라고 기술하면
    Horn : Int -> Horn
    

    라는 생성자도 이 모듈 밖에서 사용할 수 있습니다만, 여기에서는 Horn 라고 하는 형태만을 공개하고 있기 (위해)때문에, 이 생성자는 이 모듈 내부에서 밖에 사용할 수 없습니다.

    그러면 필연적으로 fromInt 이외에 Horn 형을 작성하는 수단이 없기 때문에,
    "Horn 형의 값은 반드시 염소씨의 모퉁이의 수로서 Valid이다"라고 보증됩니다.

    그럼 실제로 canMakeLove 함수를 만들어 보자!
    {-| オスとメス(順不同)の角の本数から、その2頭が交尾しても問題ないかどうかどうかを判定する関数
    -}
    canMakeLove : Horn -> Horn -> Bool
    canMakeLove (Horn n) (Horn m) =
        -- 無角同士の場合、無性のヤギが生まれてしまう可能性があるため交尾させない方が無難
        not (n == 0 && m == 0)
    

    이 라이브러리를 사용할 때는 이런 느낌이 듭니다.
    import Horn exposing (Horn)
    
    type alias Model =
        { horn1 : Int
        , horn2 : Int
        }
    
    
    message : Model -> Html Msg
    message model =
        let
            horn1 : Maybe Horn
            horn1 = Horn.fromInt model.horn1
    
            horn2 : Maybe Horn
            horn2 = Horn.fromInt model.horn2
    
            mresult : Maybe Bool
            mresult = Maybe.map2 canMakeLove horn1 horn2
        in
        div
            []
            [ text <|
                case mresult of
                    Nothing ->
                        "入力値が不正です"
    
                    Just False ->
                        "無性のヤギが生まれる可能性があり、避けたほうが良いでしょう"
    
                    Just True ->
                        "ふたりの愛をはばむものは何もありません"
            ]
    

    가족이 모인다! 했어, 염소

    사쿠라의 트위터를 따르십시오.
    다른 기사 보기
    사쿠라의 사진집을 얻는다.

    좋은 웹페이지 즐겨찾기