<p>Somewhere in the Haskell based libraries <code>String</code> is defined as a type alias as:</p>
<pre><code>type String = [Char]
</code></pre>
<p>The problem with your function is that GHC is not able to determine the type of <code>&quot;aeiou&quot;</code>. In this case you would need to add a type signature like this (untested but should work):</p>
<pre><code>vowelz :: Char -&gt; Bool
vowelz a
    | a `elem` vowels = True
    | otherwise = False
   where
     vowels :: String
     vowels = ['a','e','i','o','u']
</code></pre>

CC BY-SA 4.0
2022-02-13T20:39:29.263Z
Your solution is basically what I included in my question. The reason GHC is not able to determine the type is *because of* the OverloadedStrings language declaration. Without the OverloadedStrings and also without your solution, the code compiles just fine. My concern is around being forced to account for any arbitrary language modification when trying to write reusable code. My attitude is "if it compiles in a bare bones configuration, it should 'just work' in any configuration." Perhaps that is unrealistic, but then Haskell should not tout referential transparency.
XiTouch
CC BY-SA 4.0
2022-02-13T23:12:44.800Z
The difference is that my solution includes a type signature for `vowels` which GHC can use to resolve uncertainty in the type of that value.

This has nothing to do with referential transparency and everything to do with automated type inference.
Erik de Castro Lopo
CC BY-SA 4.0
2022-02-14T08:11:28.400Z
It sounds like the "best practice" is to not rely on type inference, and also to not assume that successfully compiled code is good enough. Thanks.
XiTouch
CC BY-SA 4.0
2022-02-14T21:05:52.550Z
As someone who has been doing Haskell professionally I would say best practice is

* All top level function should have type signatures (compiler checked documentation).
* Other type signatures when compiler needs it or for documenation.

If code compiles (ie GHC can figure out the types) it is *highly* reliable.
Erik de Castro Lopo
CC BY-SA 4.0
2022-02-13T20:12:09.940Z
2022-02-13T20:12:09.940Z
Erik de Castro Lopo
<p>One fundamental of Haskell is that a string is really a list of characters. Another fundamental is referential transparency, in that a pure function must always give the exact same result when given the same input.</p>
<p>However, these do not seem to be true in actual practice. For example, I created this function:</p>
<pre><code>stringCharList :: String -&gt; [Char] -&gt; Bool
stringCharList a b
    | a==b = True
    | otherwise = False
</code></pre>
<p>if I enter (in the repl)</p>
<pre><code>&gt;stringCharList &quot;hello&quot; ['h','e','l','l','o']
</code></pre>
<p>I get back True, as expected. However, if I build this function, I get an error (shown below)</p>
<pre><code>vowelz :: Char -&gt; Bool
vowelz a 
    | a `elem` vowels = True
    | otherwise = False
      where vowels = &quot;aeiou&quot;
</code></pre>
<pre><code>JWB2.hs:38:22: error:
    • Ambiguous type variable ‘t0’ arising from the literal ‘&quot;aeiou&quot;’
      prevents the constraint ‘(Data.String.IsString
                                  (t0 Char))’ from being solved.
      Relevant bindings include
        vowels :: t0 Char (bound at JWB2.hs:38:13)
      Probable fix: use a type annotation to specify what ‘t0’ should be.
      These potential instances exist:
        instance (a ~ Char) =&gt; Data.String.IsString [a]
          -- Defined in ‘Data.String’
        ...plus two instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the expression: &quot;aeiou&quot;
      In an equation for ‘vowels’: vowels = &quot;aeiou&quot;
      In an equation for ‘vowelz’:
          vowelz a
            | a `elem` vowels = True
            | otherwise = False
            where
                vowels = &quot;aeiou&quot;
   |
38 |       where vowels = &quot;aeiou&quot;
   |                      ^^^^^^^

</code></pre>
<p>Either of these two alternatives resolves the error</p>
<pre><code>vowelz :: Char -&gt; Bool
vowelz a
    | a `elem` vowels = True
    | otherwise = False
      where vowels = &quot;aeiou&quot; :: String

-- OR.....

vowelz :: Char -&gt; Bool
vowelz a
    | a `elem` vowels = True
    | otherwise = False
      where vowels = ['a','e','i','o','u']
</code></pre>
<p>I have tracked this down to the declaration of overloaded strings at the top of my experimental/learning hs file:</p>
<pre><code>{-# LANGUAGE OverloadedStrings #-}
</code></pre>
<p>if this line is present, I observe the issues described above. If the line is removed, the issues go away and the observed behavior is as expected.</p>
<p>It seems to me that the OverloadedStrings declaration breaks both those fundamentals I listed at the start, which makes it hard to understand how Haskell can be considered &quot;pure&quot;. It also suggests that if I want to make modular code that can be incorporated into other projects, I must account for the various hacks and kludges (and perhaps future, not-yet-invented hacks and kludges) or my pure function might break.</p>
<p>Can anyone help me wrap my brain around this?</p>

<plutus-pioneer-program><haskell>
Is type String truly equal to type [Char], and is Haskell truly "pure"?
# Is type String truly equal to type [Char], and is Haskell truly "pure"?

(Asked by: username_0 on 2022-02-13)

One fundamental of Haskell is that a string is really a list of characters. Another fundamental is referential transparency, in that a pure function must always give the exact same result when given the same input.
However, these do not seem to be true in actual practice. For example, I created this function:
stringCharList :: String -> [Char] -> Bool
stringCharList a b
    | a==b = True
    | otherwise = False

if I enter (in the repl)
>stringCharList "hello" ['h','e','l','l','o']

I get back True, as expected. However, if I build this function, I get an error (shown below)
vowelz :: Char -> Bool
vowelz a 
    | a `elem` vowels = True
    | otherwise = False
      where vowels = "aeiou"

JWB2.hs:38:22: error:
    • Ambiguous type variable ‘t0’ arising from the literal ‘"aeiou"’
      prevents the constraint ‘(Data.String.IsString
                                  (t0 Char))’ from being solved.
      Relevant bindings include
        vowels :: t0 Char (bound at JWB2.hs:38:13)
      Probable fix: use a type annotation to specify what ‘t0’ should be.
      These potential instances exist:
        instance (a ~ Char) => Data.String.IsString [a]
          -- Defined in ‘Data.String’
        ...plus two instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the expression: "aeiou"
      In an equation for ‘vowels’: vowels = "aeiou"
      In an equation for ‘vowelz’:
          vowelz a
            | a `elem` vowels = True
            | otherwise = False
            where
                vowels = "aeiou"
   |
38 |       where vowels = "aeiou"
   |                      ^^^^^^^


Either of these two alternatives resolves the error
vowelz :: Char -> Bool
vowelz a
    | a `elem` vowels = True
    | otherwise = False
      where vowels = "aeiou" :: String

-- OR.....

vowelz :: Char -> Bool
vowelz a
    | a `elem` vowels = True
    | otherwise = False
      where vowels = ['a','e','i','o','u']

I have tracked this down to the declaration of overloaded strings at the top of my experimental/learning hs file:
{-# LANGUAGE OverloadedStrings #-}

if this line is present, I observe the issues described above. If the line is removed, the issues go away and the observed behavior is as expected.
It seems to me that the OverloadedStrings declaration breaks both those fundamentals I listed at the start, which makes it hard to understand how Haskell can be considered "pure". It also suggests that if I want to make modular code that can be incorporated into other projects, I must account for the various hacks and kludges (and perhaps future, not-yet-invented hacks and kludges) or my pure function might break.
Can anyone help me wrap my brain around this?

**Tags:** plutus-pioneer-program, haskell

---

## 1 answers

### Answer by username_1 on 2022-02-13. Score: 2 | Accepted answer

Somewhere in the Haskell based libraries String is defined as a type alias as:
type String = [Char]

The problem with your function is that GHC is not able to determine the type of "aeiou". In this case you would need to add a type signature like this (untested but should work):
vowelz :: Char -> Bool
vowelz a
    | a `elem` vowels = True
    | otherwise = False
   where
     vowels :: String
     vowels = ['a','e','i','o','u']

> **Comments:**
> **username_0**: Your solution is basically what I included in my question. The reason GHC is not able to determine the type is *because of* the OverloadedStrings language declaration. Without the OverloadedStrings and also without your solution, the code compiles just fine. My concern is around being forced to account for any arbitrary language modification when trying to write reusable code. My attitude is "if it compiles in a bare bones configuration, it should 'just work' in any configuration." Perhaps that is unrealistic, but then Haskell should not tout referential transparency.  
> **username_1**: The difference is that my solution includes a type signature for `vowels` which GHC can use to resolve uncertainty in the type of that value.  This has nothing to do with referential transparency and everything to do with automated type inference.  
> **username_0**: It sounds like the "best practice" is to not rely on type inference, and also to not assume that successfully compiled code is good enough. Thanks.  
> **username_1**: As someone who has been doing Haskell professionally I would say best practice is  * All top level function should have type signatures (compiler checked documentation). * Other type signatures when compiler needs it or for documenation.  If code compiles (ie GHC can figure out the types) it is *highly* reliable.  

---

