<p>You can't use the <code>[0..tokNumLen]</code> syntax, that translates to a function from the <code>Enum</code> class from base which is not inlinable.</p>
<p>You could try something like this:</p>
<pre><code>-- Check that TokenName is of the form ABC1 .. ABC99
    checkTokenName :: TokenName -&gt;  Bool
    checkTokenName tn = lengthOfByteString bs &gt; 3
                        &amp;&amp; checkInt tokNum tokNumLen
        where
            bs = unTokenName tn
            tokNum = sliceByteString 3 2 bs
            tokNumLen = lengthOfByteString tokNum
            isNum i = Builtins.greaterThanInteger i 47 &amp;&amp; Builtins.lessThanInteger i 58
            checkInt bs' 0 = True
            checkInt bs' i = isNum (indexByteString bs' (i - 1)) &amp;&amp; checkInt bs' (i - 1)
</code></pre>

CC BY-SA 4.0
2022-02-19T10:56:43.353Z
Unfortunately it seems any attempt to use recursion results in the same error.
Avatar33
CC BY-SA 4.0
2022-02-17T09:00:24.393Z
2022-02-17T09:00:24.393Z
Sjoerd Visscher
<p>I tried to create a few modification on the NFT minting contract from week 5 of the plutus pioneer program.
I wanted to be able to mint a few tokens at once. My policy should require that the token names start with &quot;ABC&quot; + Integer where the integer is less than 100.</p>
<p>Here is my attempt:</p>
<pre><code>{-# INLINABLE mkPolicy #-}
mkPolicy :: TxOutRef -&gt; () -&gt; ScriptContext -&gt; Bool
mkPolicy oref () ctx = traceIfFalse &quot;UTxO not consumed&quot;   hasUTxO           &amp;&amp;
                          traceIfFalse &quot;wrong amount minted&quot; checkMintedAmount
  where
    info :: TxInfo
    info = scriptContextTxInfo ctx

    hasUTxO :: Bool
    hasUTxO = any (\i -&gt; txInInfoOutRef i == oref) $ txInfoInputs info

    flattenVal :: [(CurrencySymbol, TokenName, Integer)]
    flattenVal = flattenValue (txInfoMint info)

    -- Check that TokenName is of the form ABC1 .. ABC99
    checkTokenName :: TokenName -&gt;  Bool
    checkTokenName tn = isPrefixOf &quot;ABC&quot; (show tn) &amp;&amp;
                        isJust (readMaybe (post tn) :: Maybe Integer) &amp;&amp;
                        (read (post tn) :: Integer) &lt; 100
        where
            post tn' = drop 3 $ show tn'

    checkMintedAmount :: Bool
    checkMintedAmount = all (\(_, tn', amt') -&gt; checkTokenName tn' &amp;&amp; amt' == 1) flattenVal

</code></pre>
<p>Unfortunately this gives a horrible run time error which would be too long to paste here, so I'll just paste the first few lines:</p>
<pre><code>GHC Core to PLC plugin: E042:Error: Unsupported feature: Int: use Integer instead
Context: Compiling type: GHC.Types.Int
Context: Compiling type: GHC.Types.Int -&gt; a -&gt; GHC.Show.ShowS
Context: Compiling data constructor type: GHC.Show.C:Show
Context: Compiling type: GHC.Show.Show a
Context: Compiling expr: \ ($dShow_a14Ch [Occ=Once*] :: GHC.Show.Show a)
                           (tn' [Occ=Once*] :: a) -&gt;
                           let {
                             n :: GHC.Types.Int
                             [LclId,
                              Unf=Unf{Src=&lt;vanilla&gt;, TopLvl=False, Value=True, ConLike=True,
                                      WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 20}]
                             n = GHC.Types.I# 3# } in
                           letrec {
                             unsafeDrop [Occ=LoopBreaker]
                               :: forall a1. GHC.Types.Int -&gt; [a1] -&gt; [a1]
                             [LclId,
                              Arity=2,
                              Unf=Unf{Src=&lt;vanilla&gt;, TopLvl=False, Value=True, ConLike=True,
                                      WorkFree=True, Expandable=True, Guidance=IF_ARGS [20 30] 91 10}]
                             unsafeDrop
                               = \ (@ a1)
                                   (ds [Occ=Once!] :: GHC.Types.Int)
                                   (ds1 [Occ=Once!] :: [a1]) -&gt;
                                   case ds of { GHC.Types.I# ipv -&gt;
                                   case ds1 of {
                                     [] -&gt; GHC.Types.[] @ a1;
                                     : _ [Occ=Dead] ipv2 [Occ=Once*] -&gt;
                                       case ipv of {
                                         __DEFAULT -&gt;
                                           unsafeDrop @ a1 (GHC.Types.I# (GHC.Prim.-# ipv 1#)) ipv2;
                                         1# -&gt; ipv2
                                       }
                                   }
                                   }; } in
                           case GHC.Classes.leInt n (GHC.Types.I# 0#) of {
                             GHC.Types.False -&gt;
                               unsafeDrop @ GHC.Types.Char n (GHC.Show.show @ a $dShow_a14Ch tn');
                             GHC.Types.True -&gt; GHC.Show.show @ a $dShow_a14Ch tn'
                           }
</code></pre>
<p>I saw similar discussion on discord about trying to compare the token name to an empty string. Is this somehow related?
I though the above would work because I'm explicitly doing show on the BuiltinByteString</p>
<p>Any idea what I'm doing wrong?</p>
<h3>Update</h3>
<p>Someone pointed out that the compile is failing due to my onchain code not containing inlinable functions.
I think the prefix check should be doable using takeByteString and dropByteString. I'm still trying to figure out how would I check the integer part of the name? I can't find anything equivalent to ReadMaybe.</p>
<h3>Update 2</h3>
<p>I'm inching closer to a solution based on the feedback in the comments and in the Q&amp;A that happened on 15 Feb
Here is the updated attempt to use only inlinable functions</p>
<pre><code>    -- Check that TokenName is of the form ABC1 .. ABC99
    checkTokenName :: TokenName -&gt;  Bool
    checkTokenName tn = lengthOfByteString bs &gt; 3
                        &amp;&amp; checkInt tokNum
        where
            bs = unTokenName tn
            tokNum = sliceByteString 3 2 bs
            tokNumLen = lengthOfByteString tokNum
            checkInt bs' = all (\i -&gt; Builtins.greaterThanInteger i 47 &amp;&amp; Builtins.lessThanInteger i 58)
                            -- Seems this list comprehension causes issues
                            [indexByteString bs' i | i &lt;- [0..tokNumLen]]

</code></pre>
<h3>Update 3</h3>
<p>I tried the advise of Sjoerd Visscher, but unfortunately I get the same type of error if I use any function with recursion or a pattern matching.
For example</p>
<pre><code>    checkTokenName :: TokenName -&gt;  Bool
    checkTokenName tn = lengthOfByteString bs &gt; 3
                        &amp;&amp; checkInt tokNum tokNumLen
        where
            bs = unTokenName tn
            tokNum = sliceByteString 3 2 bs
            tokNumLen = lengthOfByteString tokNum
            checkInt _ 0 = True
            checkInt bs' i =  True &amp;&amp; checkInt bs' (i-1)
</code></pre>
<p>Results in:</p>
<pre><code>GHC Core to PLC plugin: E042:Error: Unsupported feature: Use of Haskell Integer equality, possibly via the Haskell Eq typeclass
Context: Compiling expr: GHC.Integer.Type.eqInteger#
Context: Compiling expr: GHC.Integer.Type.eqInteger# ds_d12x1
Context: Compiling expr: GHC.Integer.Type.eqInteger# ds_d12x1 0
Context: Compiling expr: case GHC.Integer.Type.eqInteger# ds_d12x1 0
                         of wild [Occ=Once]
                         { __DEFAULT -&gt;
                         GHC.Prim.tagToEnum# @ GHC.Types.Bool wild
                         }
...
</code></pre>
<p>It seems that only a function with no pattern matching or recursion works here.</p>
<pre><code>    checkTokenName :: TokenName -&gt;  Bool
    checkTokenName tn = lengthOfByteString bs &gt; 3
                        &amp;&amp; lengthOfByteString bs &lt; 6
                        &amp;&amp; checkInt tokNum tokNumLen
        where
            bs = unTokenName tn
            tokNum = sliceByteString 3 2 bs
            tokNumLen = lengthOfByteString tokNum
            isNum i = Builtins.greaterThanInteger i 47 &amp;&amp; Builtins.lessThanInteger i 58
            checkInt :: BuiltinByteString -&gt; Integer -&gt; Bool
            -- No recursion or pattern matching !?!? 
            checkInt bs' len = (len == 1 &amp;&amp; isNum (indexByteString bs' 0)) ||
                               (len == 2 &amp;&amp; isNum (indexByteString bs' 0) &amp;&amp;
                                            isNum (indexByteString bs' 1))

</code></pre>

CC BY-SA 4.0
2022-02-15T20:56:41.480Z
Lars gave you the answer in the Q&A if you couldn't attend. Please, check here:
https://zoom.us/rec/share/B60Bu76Ub-lSnZjOqep-_Wpo1mtgoPrMvNXIdSazQeXnGykloxjScCqxg758ITXt.I153inPX-AlAftnC
kindofdev
CC BY-SA 4.0
2022-02-16T09:34:29.687Z
Is Update 2 working? If not, could you paste the error you get?
Sjoerd Visscher
CC BY-SA 4.0
2022-02-16T12:16:04.790Z
@SjoerdVisscher Sorry, I didn't make it very obvious. Update 2 is not working. I added a comment above the list comprehension that causes an issue.  I believe it's the same error as before about not using inlinable types. I'll try update the question when I'm back at my home computer.
Avatar33
<plutus-pioneer-program>
Working with BuiltinByteString
# Working with BuiltinByteString

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

I tried to create a few modification on the NFT minting contract from week 5 of the plutus pioneer program.
I wanted to be able to mint a few tokens at once. My policy should require that the token names start with "ABC" + Integer where the integer is less than 100.

Here is my attempt:

```
{-# INLINABLE mkPolicy #-}
mkPolicy :: TxOutRef -> () -> ScriptContext -> Bool
mkPolicy oref () ctx = traceIfFalse "UTxO not consumed"   hasUTxO           &&
                          traceIfFalse "wrong amount minted" checkMintedAmount
  where
    info :: TxInfo
    info = scriptContextTxInfo ctx

    hasUTxO :: Bool
    hasUTxO = any (\i -> txInInfoOutRef i == oref) $ txInfoInputs info

    flattenVal :: [(CurrencySymbol, TokenName, Integer)]
    flattenVal = flattenValue (txInfoMint info)

    -- Check that TokenName is of the form ABC1 .. ABC99
    checkTokenName :: TokenName ->  Bool
    checkTokenName tn = isPrefixOf "ABC" (show tn) &&
                        isJust (readMaybe (post tn) :: Maybe Integer) &&
                        (read (post tn) :: Integer) < 100
        where
            post tn' = drop 3 $ show tn'

    checkMintedAmount :: Bool
    checkMintedAmount = all (\(_, tn', amt') -> checkTokenName tn' && amt' == 1) flattenVal

```

Unfortunately this gives a horrible run time error which would be too long to paste here, so I'll just paste the first few lines:

```
GHC Core to PLC plugin: E042:Error: Unsupported feature: Int: use Integer instead
Context: Compiling type: GHC.Types.Int
Context: Compiling type: GHC.Types.Int -> a -> GHC.Show.ShowS
Context: Compiling data constructor type: GHC.Show.C:Show
Context: Compiling type: GHC.Show.Show a
Context: Compiling expr: \ ($dShow_a14Ch [Occ=Once*] :: GHC.Show.Show a)
                           (tn' [Occ=Once*] :: a) ->
                           let {
                             n :: GHC.Types.Int
                             [LclId,
                              Unf=Unf{Src=<vanilla>, TopLvl=False, Value=True, ConLike=True,
                                      WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 20}]
                             n = GHC.Types.I# 3# } in
                           letrec {
                             unsafeDrop [Occ=LoopBreaker]
                               :: forall a1. GHC.Types.Int -> [a1] -> [a1]
                             [LclId,
                              Arity=2,
                              Unf=Unf{Src=<vanilla>, TopLvl=False, Value=True, ConLike=True,
                                      WorkFree=True, Expandable=True, Guidance=IF_ARGS [20 30] 91 10}]
                             unsafeDrop
                               = \ (@ a1)
                                   (ds [Occ=Once!] :: GHC.Types.Int)
                                   (ds1 [Occ=Once!] :: [a1]) ->
                                   case ds of { GHC.Types.I# ipv ->
                                   case ds1 of {
                                     [] -> GHC.Types.[] @ a1;
                                     : _ [Occ=Dead] ipv2 [Occ=Once*] ->
                                       case ipv of {
                                         __DEFAULT ->
                                           unsafeDrop @ a1 (GHC.Types.I# (GHC.Prim.-# ipv 1#)) ipv2;
                                         1# -> ipv2
                                       }
                                   }
                                   }; } in
                           case GHC.Classes.leInt n (GHC.Types.I# 0#) of {
                             GHC.Types.False ->
                               unsafeDrop @ GHC.Types.Char n (GHC.Show.show @ a $dShow_a14Ch tn');
                             GHC.Types.True -> GHC.Show.show @ a $dShow_a14Ch tn'
                           }

```

I saw similar discussion on discord about trying to compare the token name to an empty string. Is this somehow related?
I though the above would work because I'm explicitly doing show on the BuiltinByteString

Any idea what I'm doing wrong?

### Update

Someone pointed out that the compile is failing due to my onchain code not containing inlinable functions.
I think the prefix check should be doable using takeByteString and dropByteString. I'm still trying to figure out how would I check the integer part of the name? I can't find anything equivalent to ReadMaybe.

### Update 2

I'm inching closer to a solution based on the feedback in the comments and in the Q&A that happened on 15 Feb
Here is the updated attempt to use only inlinable functions

```
    -- Check that TokenName is of the form ABC1 .. ABC99
    checkTokenName :: TokenName ->  Bool
    checkTokenName tn = lengthOfByteString bs > 3
                        && checkInt tokNum
        where
            bs = unTokenName tn
            tokNum = sliceByteString 3 2 bs
            tokNumLen = lengthOfByteString tokNum
            checkInt bs' = all (\i -> Builtins.greaterThanInteger i 47 && Builtins.lessThanInteger i 58)
                            -- Seems this list comprehension causes issues
                            [indexByteString bs' i | i <- [0..tokNumLen]]

```

### Update 3

I tried the advise of username_2 username_2, but unfortunately I get the same type of error if I use any function with recursion or a pattern matching.
For example

```
    checkTokenName :: TokenName ->  Bool
    checkTokenName tn = lengthOfByteString bs > 3
                        && checkInt tokNum tokNumLen
        where
            bs = unTokenName tn
            tokNum = sliceByteString 3 2 bs
            tokNumLen = lengthOfByteString tokNum
            checkInt _ 0 = True
            checkInt bs' i =  True && checkInt bs' (i-1)

```

Results in:

```
GHC Core to PLC plugin: E042:Error: Unsupported feature: Use of Haskell Integer equality, possibly via the Haskell Eq typeclass
Context: Compiling expr: GHC.Integer.Type.eqInteger#
Context: Compiling expr: GHC.Integer.Type.eqInteger# ds_d12x1
Context: Compiling expr: GHC.Integer.Type.eqInteger# ds_d12x1 0
Context: Compiling expr: case GHC.Integer.Type.eqInteger# ds_d12x1 0
                         of wild [Occ=Once]
                         { __DEFAULT ->
                         GHC.Prim.tagToEnum# @ GHC.Types.Bool wild
                         }
...

```

It seems that only a function with no pattern matching or recursion works here.

```
    checkTokenName :: TokenName ->  Bool
    checkTokenName tn = lengthOfByteString bs > 3
                        && lengthOfByteString bs < 6
                        && checkInt tokNum tokNumLen
        where
            bs = unTokenName tn
            tokNum = sliceByteString 3 2 bs
            tokNumLen = lengthOfByteString tokNum
            isNum i = Builtins.greaterThanInteger i 47 && Builtins.lessThanInteger i 58
            checkInt :: BuiltinByteString -> Integer -> Bool
            -- No recursion or pattern matching !?!? 
            checkInt bs' len = (len == 1 && isNum (indexByteString bs' 0)) ||
                               (len == 2 && isNum (indexByteString bs' 0) &&
                                            isNum (indexByteString bs' 1))

```

**Tags:** plutus-pioneer-program

> **Comments:**
> **username_1**: Lars gave you the answer in the Q&A if you couldn't attend. Please, check here: https://zoom.us/rec/share/B60Bu76Ub-lSnZjOqep-_Wpo1mtgoPrMvNXIdSazQeXnGykloxjScCqxg758ITXt.I153inPX-AlAftnC  
> **username_2**: Is Update 2 working? If not, could you paste the error you get?  
> **username_0**: @username_2 Sorry, I didn't make it very obvious. Update 2 is not working. I added a comment above the list comprehension that causes an issue.  I believe it's the same error as before about not using inlinable types. I'll try update the question when I'm back at my home computer.  

---

## 1 answers

### Answer by username_2 on 2022-02-17. Score: 1

You can't use the `[0..tokNumLen]` syntax, that translates to a function from the `Enum` class from base which is not inlinable.

You could try something like this:

```
-- Check that TokenName is of the form ABC1 .. ABC99
    checkTokenName :: TokenName ->  Bool
    checkTokenName tn = lengthOfByteString bs > 3
                        && checkInt tokNum tokNumLen
        where
            bs = unTokenName tn
            tokNum = sliceByteString 3 2 bs
            tokNumLen = lengthOfByteString tokNum
            isNum i = Builtins.greaterThanInteger i 47 && Builtins.lessThanInteger i 58
            checkInt bs' 0 = True
            checkInt bs' i = isNum (indexByteString bs' (i - 1)) && checkInt bs' (i - 1)

```

> **Comments:**
> **username_0**: Unfortunately it seems any attempt to use recursion results in the same error.  

---

