70036


## コード

下記のように自作のMaybeぽいものを作ってみました。

[code]

    data MayNull a = Have a | Null deriving Show
    
    incMayNull (Have x) = x + 1
    incMayNull Null = Null
    
    v = Have 1
    foo = incMayNull v
    
    main = do print foo
    
[/code]

## 実行結果

実行すると下記エラーです。 `Have`の中から値を取り出し `+1` できる関数を定義できていると思ったのですが、なにがいけないんでしょうか？

% docker run -it --rm --name bar-haskell -v "$PWD":/tmp -w /tmp haskell:8
runghc Bar.hs

[code]

    Bar.hs:3:1: error:
        * Non type-variable argument in the constraint: Num (MayNull a)
          (Use FlexibleContexts to permit this)
        * When checking the inferred type
            incMayNull :: forall a.
                          Num (MayNull a) =>
                          MayNull (MayNull a) -> MayNull a
      |
    3 | incMayNull (Have x) = x + 1
      | ^^^^^^^^^^^^^^^^^^^^^^^^^^^...
    
    Bar.hs:9:11: error:
        * Ambiguous type variable `a0' arising from a use of `print'
          prevents the constraint `(Show a0)' from being solved.
          Probable fix: use a type annotation to specify what `a0' should be.
          These potential instances exist:
            instance Show Ordering -- Defined in `GHC.Show'
            instance Show Integer -- Defined in `GHC.Show'
            instance Show a => Show (MayNull a) -- Defined at Bar.hs:1:41
            ...plus 23 others
            ...plus 12 instances involving out-of-scope types
            (use -fprint-potential-instances to see them all)
        * In a stmt of a 'do' block: print foo
          In the expression: do print foo
          In an equation for `main': main = do print foo
      |
    9 | main = do print foo
      |           ^^^^^^^^^
    
[/code]


CC BY-SA 4.0
2020-09-01T00:41:27.743
70029
2020-09-01T03:59:21.337
9008
question
haskell
error: Non type-variable argument in the constraint: Num (MayNull a) (Use FlexibleContexts to permit this)というエラーが出る


2つエラーがあり，それぞれ原因が違います．

**1つ目** : `Use FlexibleContexts to permit this`
のやつで，このエラー自体についてはいろいろ事情があるのですが， 直接の原因は typo だと思います．

[code]

    incMayNull (Have x) = Have $ x + 1
    incMayNull Null = Null
    
[/code]

ですよね？ （ここで `Have`
が抜けていることと，下に書いた数値リテラルが多相であることにより，我々が想定しない複雑な型推論を頑張ってくれた結果が上記のエラーです）

**2つ目** まず前提として，たぶん `1` が思っておられるのと異なります ． GHCi を開いて

[code]

    Prelude> let a = 1
    Prelude> :i a
    a :: Num p => p     -- Defined at <interactive>:2:5
    
[/code]

としていただくとわかるとおり，じつは整数を書いていると思っているそれは `Num` について多相です（部脈次第で Num
のインスタンスであるどれかの型に定まりますが，それは `Int` とは限りません）．

たとえば次のようなことができます．

[code]

    data Foo = Foo deriving (Show)
    
    instance Num Foo where
        Foo + Foo = Foo
        fromInteger _ = Foo
        -- ほんとはもっといろいろ定義する必要がありますが
    
    main = do
        print $ Foo + 1
        print (1 :: Foo)
    
    
[/code]

…なのですが，上の `Have` を修正すると2つ目のエラーもでなくなります．これは，とはいえ，ふつうはいい感じにデフォルトを推論してくれるからです．

[code]

    $ ghc  -Wtype-defaults a.hs
    [1 of 1] Compiling Main             ( a.hs, a.o )
    
    a.hs:6:10: warning: [-Wtype-defaults]
        • Defaulting the following constraints to type ‘Integer’
            (Num a0) arising from the literal ‘1’ at a.hs:6:10
            (Num a0) arising from a use of ‘incMayNull’ at a.hs:7:7-18
            (Show a0) arising from a use of ‘print’ at a.hs:9:11-19
        • In the first argument of ‘Have’, namely ‘1’
          In the expression: Have 1
          In an equation for ‘v’: v = Have 1
      |
    6 | v = Have 1
    
[/code]

`Integer` だとおもってくれるので（`Int`でないことには注意），予想通りに動きます．


CC BY-SA 4.0
2020-09-01T03:59:21.337
70036
2020-09-01T03:59:21.337
2901
70029
answer