Haskell function with different number of argument












1














I'm trying to create a Haskell function with a class to get this function to work with different numbers of arguments.



{-# Language FlexibleInstances #-}

class Titles a where
titleTeX :: String -> a

instance Titles String where
titleTeX str = titleWithFrame 1 "%" "%" "%" [str]

instance Titles (String -> String) where
titleTeX str = (s -> titleWithFrame 1 "%" "%" "%" (s:[str]))

titleWithFrame::Int -> String -> String -> String -> [String] -> String
titleWithFrame nb beg end com lstr =
cadr++cont++cadr
where
cadr = concat $ replicate nb (beg++rempl++end++"n")
cont = concatMap (s -> beg++" "++s++" "++end++"n") lstr
rempl = take long $ concat $ replicate long com
long = (maximum $ map length lstr) + 2


When I try this function with ghci, I have the following results:



ghci> putStr $ titleTeX "Line 1"
%%%%%%%%%%
% Line 1 %
%%%%%%%%%%
ghci> putStr $ titleTeX "Line 1" "Line 2"
%%%%%%%%%%
% Line 1 %
% Line 2 %
%%%%%%%%%%
ghci> putStr $ titleTeX "Line 1" "Line 2" "Line 3"

<interactive>:4:10: error:
• No instance for (Main.Titles ([Char] -> [Char] -> String))
arising from a use of ‘titleTeX’
(maybe you haven't applied a function to enough arguments?)
• In the second argument of ‘($)’, namely
‘titleTeX "Line 1" "Line 2" "Line 3"’
In the expression: putStr $ titleTeX "Line 1" "Line 2" "Line 3"
In an equation for ‘it’:
it = putStr $ titleTeX "Line 1" "Line 2" "Line 3"


I don't understand where my error is and why my polyvariadic function doesn't work with more than 2 arguments.



Do you know where my error comes from? and How to make my function work with an arbitrary number of arguments?










share|improve this question
























  • My question was not correctly described. I have modified my question.
    – JeanJouX
    Nov 23 '18 at 21:45
















1














I'm trying to create a Haskell function with a class to get this function to work with different numbers of arguments.



{-# Language FlexibleInstances #-}

class Titles a where
titleTeX :: String -> a

instance Titles String where
titleTeX str = titleWithFrame 1 "%" "%" "%" [str]

instance Titles (String -> String) where
titleTeX str = (s -> titleWithFrame 1 "%" "%" "%" (s:[str]))

titleWithFrame::Int -> String -> String -> String -> [String] -> String
titleWithFrame nb beg end com lstr =
cadr++cont++cadr
where
cadr = concat $ replicate nb (beg++rempl++end++"n")
cont = concatMap (s -> beg++" "++s++" "++end++"n") lstr
rempl = take long $ concat $ replicate long com
long = (maximum $ map length lstr) + 2


When I try this function with ghci, I have the following results:



ghci> putStr $ titleTeX "Line 1"
%%%%%%%%%%
% Line 1 %
%%%%%%%%%%
ghci> putStr $ titleTeX "Line 1" "Line 2"
%%%%%%%%%%
% Line 1 %
% Line 2 %
%%%%%%%%%%
ghci> putStr $ titleTeX "Line 1" "Line 2" "Line 3"

<interactive>:4:10: error:
• No instance for (Main.Titles ([Char] -> [Char] -> String))
arising from a use of ‘titleTeX’
(maybe you haven't applied a function to enough arguments?)
• In the second argument of ‘($)’, namely
‘titleTeX "Line 1" "Line 2" "Line 3"’
In the expression: putStr $ titleTeX "Line 1" "Line 2" "Line 3"
In an equation for ‘it’:
it = putStr $ titleTeX "Line 1" "Line 2" "Line 3"


I don't understand where my error is and why my polyvariadic function doesn't work with more than 2 arguments.



Do you know where my error comes from? and How to make my function work with an arbitrary number of arguments?










share|improve this question
























  • My question was not correctly described. I have modified my question.
    – JeanJouX
    Nov 23 '18 at 21:45














1












1








1







I'm trying to create a Haskell function with a class to get this function to work with different numbers of arguments.



{-# Language FlexibleInstances #-}

class Titles a where
titleTeX :: String -> a

instance Titles String where
titleTeX str = titleWithFrame 1 "%" "%" "%" [str]

instance Titles (String -> String) where
titleTeX str = (s -> titleWithFrame 1 "%" "%" "%" (s:[str]))

titleWithFrame::Int -> String -> String -> String -> [String] -> String
titleWithFrame nb beg end com lstr =
cadr++cont++cadr
where
cadr = concat $ replicate nb (beg++rempl++end++"n")
cont = concatMap (s -> beg++" "++s++" "++end++"n") lstr
rempl = take long $ concat $ replicate long com
long = (maximum $ map length lstr) + 2


When I try this function with ghci, I have the following results:



ghci> putStr $ titleTeX "Line 1"
%%%%%%%%%%
% Line 1 %
%%%%%%%%%%
ghci> putStr $ titleTeX "Line 1" "Line 2"
%%%%%%%%%%
% Line 1 %
% Line 2 %
%%%%%%%%%%
ghci> putStr $ titleTeX "Line 1" "Line 2" "Line 3"

<interactive>:4:10: error:
• No instance for (Main.Titles ([Char] -> [Char] -> String))
arising from a use of ‘titleTeX’
(maybe you haven't applied a function to enough arguments?)
• In the second argument of ‘($)’, namely
‘titleTeX "Line 1" "Line 2" "Line 3"’
In the expression: putStr $ titleTeX "Line 1" "Line 2" "Line 3"
In an equation for ‘it’:
it = putStr $ titleTeX "Line 1" "Line 2" "Line 3"


I don't understand where my error is and why my polyvariadic function doesn't work with more than 2 arguments.



Do you know where my error comes from? and How to make my function work with an arbitrary number of arguments?










share|improve this question















I'm trying to create a Haskell function with a class to get this function to work with different numbers of arguments.



{-# Language FlexibleInstances #-}

class Titles a where
titleTeX :: String -> a

instance Titles String where
titleTeX str = titleWithFrame 1 "%" "%" "%" [str]

instance Titles (String -> String) where
titleTeX str = (s -> titleWithFrame 1 "%" "%" "%" (s:[str]))

titleWithFrame::Int -> String -> String -> String -> [String] -> String
titleWithFrame nb beg end com lstr =
cadr++cont++cadr
where
cadr = concat $ replicate nb (beg++rempl++end++"n")
cont = concatMap (s -> beg++" "++s++" "++end++"n") lstr
rempl = take long $ concat $ replicate long com
long = (maximum $ map length lstr) + 2


When I try this function with ghci, I have the following results:



ghci> putStr $ titleTeX "Line 1"
%%%%%%%%%%
% Line 1 %
%%%%%%%%%%
ghci> putStr $ titleTeX "Line 1" "Line 2"
%%%%%%%%%%
% Line 1 %
% Line 2 %
%%%%%%%%%%
ghci> putStr $ titleTeX "Line 1" "Line 2" "Line 3"

<interactive>:4:10: error:
• No instance for (Main.Titles ([Char] -> [Char] -> String))
arising from a use of ‘titleTeX’
(maybe you haven't applied a function to enough arguments?)
• In the second argument of ‘($)’, namely
‘titleTeX "Line 1" "Line 2" "Line 3"’
In the expression: putStr $ titleTeX "Line 1" "Line 2" "Line 3"
In an equation for ‘it’:
it = putStr $ titleTeX "Line 1" "Line 2" "Line 3"


I don't understand where my error is and why my polyvariadic function doesn't work with more than 2 arguments.



Do you know where my error comes from? and How to make my function work with an arbitrary number of arguments?







haskell typeclass polyvariadic






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 23 '18 at 22:16









melpomene

58.7k54489




58.7k54489










asked Nov 23 '18 at 1:20









JeanJouX

1,16911429




1,16911429












  • My question was not correctly described. I have modified my question.
    – JeanJouX
    Nov 23 '18 at 21:45


















  • My question was not correctly described. I have modified my question.
    – JeanJouX
    Nov 23 '18 at 21:45
















My question was not correctly described. I have modified my question.
– JeanJouX
Nov 23 '18 at 21:45




My question was not correctly described. I have modified my question.
– JeanJouX
Nov 23 '18 at 21:45












2 Answers
2






active

oldest

votes


















1














The error occurs because you have exactly two instances of Titles in your program:



instance Titles String
instance Titles (String -> String)


These let you call titleTeX with one and two arguments respectively, but three arguments would require



instance Titles (String -> String -> String)


which doesn't exist. Or as ghc puts it:



• No instance for (Main.Titles ([Char] -> [Char] -> String))
arising from a use of ‘titleTeX’


([Char] is the same as String.)



It's as if you'd defined a function



foo :: [Int] -> Int
foo [x] = ...
foo [x, y] = ...


but foo [x, y, z] is an error.



To make this work for any number of arguments, we need to use recursion. As with list functions (where you'd typically have a base case foo = ... and a recursive case foo (x : xs) = ... that calls foo xs somewhere), we need to define a Titles instance in terms of other instances:



instance Titles String
instance (Titles a) => Titles (String -> a)


The tricky bit is that I don't see a way to implement a titleTeX that fits the above declarations.



I had to make other changes to your code to make it work:



{-# Language FlexibleInstances #-}

titleTeX :: (Titles a) => String -> a
titleTeX str = titleTeXAccum [str]


titleTeX isn't a method anymore. It's just a convenience front-end for the actual titleTeXAccum method.



In principle we could have omitted the String parameter and defined titleTeX :: (Titles a) => a as titleTeX = titleTexAccum , but then titleTex :: String would crash at runtime (because we end up calling maximum on an empty list).



class Titles a where
titleTeXAccum :: [String] -> a


Our method now takes a list of strings that it (somehow) turns into a value of type a.



instance Titles String where
titleTeXAccum acc = titleWithFrame 1 "%" "%" "%" (reverse acc)


The implementation for String is easy: We just call titleWithFrame. We also pass reverse acc because the order of elements in the accumulator is backwards (see below).



instance (Titles a) => Titles (String -> a) where
titleTeXAccum acc str = titleTeXAccum (str : acc)


This is the crucial part: The general titleTeXAccum method forwards to another titleTeXAccum method (of a different type / different Titles instance). It adds str to the accumulator. We could have written acc ++ [str] to add the new element at the end, but that's inefficient: Calling titleTeXAccum with N elements would take O(N^2) time (due to repeated list traversals in ++). Using : and only calling reverse once at the end reduces this to O(N).






share|improve this answer





















  • Perfect and well detailed answer!
    – JeanJouX
    Nov 24 '18 at 14:15



















2














It works if you use the function you presented, titleTeX, and not some other function you have yet to show, titleLaTeX.






share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53439643%2fhaskell-function-with-different-number-of-argument%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    The error occurs because you have exactly two instances of Titles in your program:



    instance Titles String
    instance Titles (String -> String)


    These let you call titleTeX with one and two arguments respectively, but three arguments would require



    instance Titles (String -> String -> String)


    which doesn't exist. Or as ghc puts it:



    • No instance for (Main.Titles ([Char] -> [Char] -> String))
    arising from a use of ‘titleTeX’


    ([Char] is the same as String.)



    It's as if you'd defined a function



    foo :: [Int] -> Int
    foo [x] = ...
    foo [x, y] = ...


    but foo [x, y, z] is an error.



    To make this work for any number of arguments, we need to use recursion. As with list functions (where you'd typically have a base case foo = ... and a recursive case foo (x : xs) = ... that calls foo xs somewhere), we need to define a Titles instance in terms of other instances:



    instance Titles String
    instance (Titles a) => Titles (String -> a)


    The tricky bit is that I don't see a way to implement a titleTeX that fits the above declarations.



    I had to make other changes to your code to make it work:



    {-# Language FlexibleInstances #-}

    titleTeX :: (Titles a) => String -> a
    titleTeX str = titleTeXAccum [str]


    titleTeX isn't a method anymore. It's just a convenience front-end for the actual titleTeXAccum method.



    In principle we could have omitted the String parameter and defined titleTeX :: (Titles a) => a as titleTeX = titleTexAccum , but then titleTex :: String would crash at runtime (because we end up calling maximum on an empty list).



    class Titles a where
    titleTeXAccum :: [String] -> a


    Our method now takes a list of strings that it (somehow) turns into a value of type a.



    instance Titles String where
    titleTeXAccum acc = titleWithFrame 1 "%" "%" "%" (reverse acc)


    The implementation for String is easy: We just call titleWithFrame. We also pass reverse acc because the order of elements in the accumulator is backwards (see below).



    instance (Titles a) => Titles (String -> a) where
    titleTeXAccum acc str = titleTeXAccum (str : acc)


    This is the crucial part: The general titleTeXAccum method forwards to another titleTeXAccum method (of a different type / different Titles instance). It adds str to the accumulator. We could have written acc ++ [str] to add the new element at the end, but that's inefficient: Calling titleTeXAccum with N elements would take O(N^2) time (due to repeated list traversals in ++). Using : and only calling reverse once at the end reduces this to O(N).






    share|improve this answer





















    • Perfect and well detailed answer!
      – JeanJouX
      Nov 24 '18 at 14:15
















    1














    The error occurs because you have exactly two instances of Titles in your program:



    instance Titles String
    instance Titles (String -> String)


    These let you call titleTeX with one and two arguments respectively, but three arguments would require



    instance Titles (String -> String -> String)


    which doesn't exist. Or as ghc puts it:



    • No instance for (Main.Titles ([Char] -> [Char] -> String))
    arising from a use of ‘titleTeX’


    ([Char] is the same as String.)



    It's as if you'd defined a function



    foo :: [Int] -> Int
    foo [x] = ...
    foo [x, y] = ...


    but foo [x, y, z] is an error.



    To make this work for any number of arguments, we need to use recursion. As with list functions (where you'd typically have a base case foo = ... and a recursive case foo (x : xs) = ... that calls foo xs somewhere), we need to define a Titles instance in terms of other instances:



    instance Titles String
    instance (Titles a) => Titles (String -> a)


    The tricky bit is that I don't see a way to implement a titleTeX that fits the above declarations.



    I had to make other changes to your code to make it work:



    {-# Language FlexibleInstances #-}

    titleTeX :: (Titles a) => String -> a
    titleTeX str = titleTeXAccum [str]


    titleTeX isn't a method anymore. It's just a convenience front-end for the actual titleTeXAccum method.



    In principle we could have omitted the String parameter and defined titleTeX :: (Titles a) => a as titleTeX = titleTexAccum , but then titleTex :: String would crash at runtime (because we end up calling maximum on an empty list).



    class Titles a where
    titleTeXAccum :: [String] -> a


    Our method now takes a list of strings that it (somehow) turns into a value of type a.



    instance Titles String where
    titleTeXAccum acc = titleWithFrame 1 "%" "%" "%" (reverse acc)


    The implementation for String is easy: We just call titleWithFrame. We also pass reverse acc because the order of elements in the accumulator is backwards (see below).



    instance (Titles a) => Titles (String -> a) where
    titleTeXAccum acc str = titleTeXAccum (str : acc)


    This is the crucial part: The general titleTeXAccum method forwards to another titleTeXAccum method (of a different type / different Titles instance). It adds str to the accumulator. We could have written acc ++ [str] to add the new element at the end, but that's inefficient: Calling titleTeXAccum with N elements would take O(N^2) time (due to repeated list traversals in ++). Using : and only calling reverse once at the end reduces this to O(N).






    share|improve this answer





















    • Perfect and well detailed answer!
      – JeanJouX
      Nov 24 '18 at 14:15














    1












    1








    1






    The error occurs because you have exactly two instances of Titles in your program:



    instance Titles String
    instance Titles (String -> String)


    These let you call titleTeX with one and two arguments respectively, but three arguments would require



    instance Titles (String -> String -> String)


    which doesn't exist. Or as ghc puts it:



    • No instance for (Main.Titles ([Char] -> [Char] -> String))
    arising from a use of ‘titleTeX’


    ([Char] is the same as String.)



    It's as if you'd defined a function



    foo :: [Int] -> Int
    foo [x] = ...
    foo [x, y] = ...


    but foo [x, y, z] is an error.



    To make this work for any number of arguments, we need to use recursion. As with list functions (where you'd typically have a base case foo = ... and a recursive case foo (x : xs) = ... that calls foo xs somewhere), we need to define a Titles instance in terms of other instances:



    instance Titles String
    instance (Titles a) => Titles (String -> a)


    The tricky bit is that I don't see a way to implement a titleTeX that fits the above declarations.



    I had to make other changes to your code to make it work:



    {-# Language FlexibleInstances #-}

    titleTeX :: (Titles a) => String -> a
    titleTeX str = titleTeXAccum [str]


    titleTeX isn't a method anymore. It's just a convenience front-end for the actual titleTeXAccum method.



    In principle we could have omitted the String parameter and defined titleTeX :: (Titles a) => a as titleTeX = titleTexAccum , but then titleTex :: String would crash at runtime (because we end up calling maximum on an empty list).



    class Titles a where
    titleTeXAccum :: [String] -> a


    Our method now takes a list of strings that it (somehow) turns into a value of type a.



    instance Titles String where
    titleTeXAccum acc = titleWithFrame 1 "%" "%" "%" (reverse acc)


    The implementation for String is easy: We just call titleWithFrame. We also pass reverse acc because the order of elements in the accumulator is backwards (see below).



    instance (Titles a) => Titles (String -> a) where
    titleTeXAccum acc str = titleTeXAccum (str : acc)


    This is the crucial part: The general titleTeXAccum method forwards to another titleTeXAccum method (of a different type / different Titles instance). It adds str to the accumulator. We could have written acc ++ [str] to add the new element at the end, but that's inefficient: Calling titleTeXAccum with N elements would take O(N^2) time (due to repeated list traversals in ++). Using : and only calling reverse once at the end reduces this to O(N).






    share|improve this answer












    The error occurs because you have exactly two instances of Titles in your program:



    instance Titles String
    instance Titles (String -> String)


    These let you call titleTeX with one and two arguments respectively, but three arguments would require



    instance Titles (String -> String -> String)


    which doesn't exist. Or as ghc puts it:



    • No instance for (Main.Titles ([Char] -> [Char] -> String))
    arising from a use of ‘titleTeX’


    ([Char] is the same as String.)



    It's as if you'd defined a function



    foo :: [Int] -> Int
    foo [x] = ...
    foo [x, y] = ...


    but foo [x, y, z] is an error.



    To make this work for any number of arguments, we need to use recursion. As with list functions (where you'd typically have a base case foo = ... and a recursive case foo (x : xs) = ... that calls foo xs somewhere), we need to define a Titles instance in terms of other instances:



    instance Titles String
    instance (Titles a) => Titles (String -> a)


    The tricky bit is that I don't see a way to implement a titleTeX that fits the above declarations.



    I had to make other changes to your code to make it work:



    {-# Language FlexibleInstances #-}

    titleTeX :: (Titles a) => String -> a
    titleTeX str = titleTeXAccum [str]


    titleTeX isn't a method anymore. It's just a convenience front-end for the actual titleTeXAccum method.



    In principle we could have omitted the String parameter and defined titleTeX :: (Titles a) => a as titleTeX = titleTexAccum , but then titleTex :: String would crash at runtime (because we end up calling maximum on an empty list).



    class Titles a where
    titleTeXAccum :: [String] -> a


    Our method now takes a list of strings that it (somehow) turns into a value of type a.



    instance Titles String where
    titleTeXAccum acc = titleWithFrame 1 "%" "%" "%" (reverse acc)


    The implementation for String is easy: We just call titleWithFrame. We also pass reverse acc because the order of elements in the accumulator is backwards (see below).



    instance (Titles a) => Titles (String -> a) where
    titleTeXAccum acc str = titleTeXAccum (str : acc)


    This is the crucial part: The general titleTeXAccum method forwards to another titleTeXAccum method (of a different type / different Titles instance). It adds str to the accumulator. We could have written acc ++ [str] to add the new element at the end, but that's inefficient: Calling titleTeXAccum with N elements would take O(N^2) time (due to repeated list traversals in ++). Using : and only calling reverse once at the end reduces this to O(N).







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 23 '18 at 22:35









    melpomene

    58.7k54489




    58.7k54489












    • Perfect and well detailed answer!
      – JeanJouX
      Nov 24 '18 at 14:15


















    • Perfect and well detailed answer!
      – JeanJouX
      Nov 24 '18 at 14:15
















    Perfect and well detailed answer!
    – JeanJouX
    Nov 24 '18 at 14:15




    Perfect and well detailed answer!
    – JeanJouX
    Nov 24 '18 at 14:15













    2














    It works if you use the function you presented, titleTeX, and not some other function you have yet to show, titleLaTeX.






    share|improve this answer


























      2














      It works if you use the function you presented, titleTeX, and not some other function you have yet to show, titleLaTeX.






      share|improve this answer
























        2












        2








        2






        It works if you use the function you presented, titleTeX, and not some other function you have yet to show, titleLaTeX.






        share|improve this answer












        It works if you use the function you presented, titleTeX, and not some other function you have yet to show, titleLaTeX.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 23 '18 at 2:29









        Thomas M. DuBuisson

        54.3k688150




        54.3k688150






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53439643%2fhaskell-function-with-different-number-of-argument%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Berounka

            Sphinx de Gizeh

            Different font size/position of beamer's navigation symbols template's content depending on regular/plain...