簡體   English   中英

初學者Haskell問題(沒有實例......來自)

[英]Beginner Haskell problems (No instance for … arising from)

我最近開始學習Haskell,我正在嘗試重寫我在Haskell中使用python進行訪談時所做的一些事情。 我正在嘗試將字符串從camel case轉換為下划線(“myVariableName” - >“my_variable_name”),如果第一個字符為大寫,則會拋出錯誤。

這就是我所擁有的:

import qualified Data.Char as Char

translate_java :: String -> String
translate_java xs = translate_helper $ enumerate xs
    where 
        translate_helper [] = []
        translate_helper ((a, num):xs)
            | num == 1 and Char.isUpper a = error "cannot start with upper"
            | Char.isUpper a              = '_' : Char.toLower a : translate_helper xs
            | otherwise                   = a : translate_helper xs


enumerate :: (Num b, Enum b) => [a] -> [(a,b)]
enumerate xs = zip xs [1..]

我意識到我很可能會以一種奇怪的方式解決這個問題,而且我喜歡有關更好的方法來實現這一點的建議,但我也希望能夠編譯它。 這是我現在得到的錯誤:

Prelude> :r
[1 of 1] Compiling Main             ( translate.hs, interpreted )

translate.hs:4:20:
    No instance for (Num
                       (([Bool] -> Bool) -> (Char -> Bool) -> Char -> t))
      arising from a use of `translate_helper' at translate.hs:4:20-35
    Possible fix:
      add an instance declaration for
      (Num (([Bool] -> Bool) -> (Char -> Bool) -> Char -> t))
    In the first argument of `($)', namely `translate_helper'
    In the expression: translate_helper $ enumerate xs
    In the definition of `translate_java':
        translate_java xs
                         = translate_helper $ enumerate xs
                         where
                             translate_helper [] = []
                             translate_helper ((a, num) : xs)
                                                | num == 1 and Char.isUpper a
                                                = error "cannot start with upper
"
                                                | Char.isUpper a
                                                = '_' : Char.toLower a : transla
te_helper xs
                                                | otherwise = a : translate_help
er xs
Failed, modules loaded: none.

對這里發生的事情的任何解釋都會很棒。 我真的不明白“(Num(([Bool] - > Bool) - >(Char - > Bool) - > Char - > t))”來自。 我認為translate_helper的類型聲明類似於[(a,b)] - > [a]?

你必須更換and通過&& 第一個是一個函數(前綴),它接收一個布爾值列表並計算它們的全部。 第二個是真正的邏輯和。 但錯誤消息有點令人困惑。 每當我收到如此奇怪的錯誤消息時,我通常會開始使用類型簽名來注釋我的代碼。 然后編譯器能夠為您提供更詳細的錯誤描述。

其他人提到你應該使用(&&)代替and ,所以我會回答你的另一個問題:不,我不認為你會以一種奇怪的方式解決這個問題。

但是......我覺得它可以優雅!

translate_java (x:xs) | isUpper x = error "cannot start with an upper"
translate_java xs = concatMap translate xs where
    translate x = ['_' | isUpper x] ++ [toLower x]

這里有一些有趣的事情:

  1. 特殊情況立即檢查。 不要等到你再次做到這一點!
  2. concatMap函數在很多情況下非常方便。 它只是一張map后面是一個concat 如果我自己寫這篇文章,我可能會使用xs >>= translate
  3. ['_' | isUpper x] ['_' | isUpper x]是一個列表理解; 這是一個可愛的習慣用法,用於制作一個包含0或1個元素的列表,具體取決於謂詞是否成立。

除此之外,代碼應該是相當不言自明的。

問題是這樣的:

| num == 1 and Char.isUpper a = ...

and不是中綴運營商; 相反它是一個功能:

and :: [Bool] -> Bool

所以它解釋1 and Char.isUpper a將三個參數應用於“function” 1 請改用&&

錯誤消息來自解釋數字的方式。 數字,比方說, 1實際上是多態的; 它獲得的具體類型取決於所需的類型。 這就是為什么你可以說x+1 ,無論x是整數還是雙精度,它都能正常工作。 因此編譯器推斷1的類型需要是一個三參數函數,然后嘗試找到匹配的數字類型,以便它可以將1轉換為該類型(當然,失敗)。

這是我的解決方案。 它不像Daniel Wagner使用concatMap和列表理解所給出的那樣精湛,但對初學者來說可能更容易理解。

conv :: String -> String
conv [] = []
conv s@(x:xs) = if Char.isUpper x 
                then error "First character cannot be uppercase"
                else change s

change :: String -> String
change [] = []
change (x:xs) = if Char.isUpper x 
                then '_' : Char.toLower x : change xs 
                else x : change xs

函數conv實際上只是檢查你的標准,即第一個字符不能是大寫的,如果不是,它將字符串交給函數更改,這就完成了工作。 它逐個遍歷所有字符,構建一個列表,如果字符是大寫的,它會添加一個下划線,后跟字符的小寫版本,否則如果字符已經是小寫,則只需按原樣添加即可。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM