我有以下問題。我有一個很好用的功能。
getName :: Style -> Css -> Maybe String
getName s css = map intToChar . intToBase 26 <$> getIndex s css
我想知道為什么我不能這樣定義:
getName :: Style -> Css -> Maybe String
getName = map intToChar . intToBase 26 <$> getIndex
我認為 currying 將允許我將其作為帶有兩個引數的函式回傳,而不是作為具有兩個引數的函式
如果它有助于您的理解:
intToChar :: Int -> Char
intToBase :: Int -> Int -> [Int]
getIndex :: Style > Css -> Maybe Int
啊不要忘記錯誤:
error:
? Couldn't match type ‘[a] -> Maybe Int’ with ‘Int’
Expected type: a -> Int
Actual type: a -> [a] -> Maybe Int
? Probable cause: ‘getIndex’ is applied to too few arguments
In the second argument of ‘(<$>)’, namely ‘getIndex’
In the expression: map intToChar . intToBase 26 <$> getIndex
In an equation for ‘getName’:
getName = map intToChar . intToBase 26 <$> getIndex
? Relevant bindings include
getName :: a -> [Char] (bound at src/Css/Css.hs:17:1)
|
17 | getName = map intToChar . intToBase 26 <$> getIndex
| ^^^^^^^^
uj5u.com熱心網友回復:
問題是sandcss不能通過eta 轉換消除,因為它們被用作getIndex單獨的引數,而不是map intToChar . intToBase 26 <$> getIndex.
要實作無點,您必須使用函陣列合。首先,使用fmap而不是重寫您的定義<$>(并將不相關的引數fmap隱藏在區域變數后面)。
getName s css = fmap f (getIndex s css)
where f = map intToChar . intToBase 26
現在更容易看出您需要使用函陣列合來首先消除css:
-- f1 (f2 x) == f1 . f2
-- f1 = fmap f
-- f2 = getIndex s
getName s = fmap f . (getIndex s)
where f = map intToChar . intToBase 26
然后s:
-- f1 (f2 x) = f1 . f2
-- f1 = (fmap f .)
-- f2 = getIndex
getName = (fmap f . ) . getIndex
where f = map intToChar . intToBase 26
uj5u.com熱心網友回復:
也許一些括號是有序的。首先,您嘗試應用的原則是有效的。也就是說,如果一個變數是你的函式的最后一個引數并且是你的函式中頂級呼叫的最后一個引數,你可以有效地“右取消”這兩個變數,所以如果你有
prependMy x = mappend "my" x
然后你可以安全地“取消”x并獲得等價的(模單態限制,這里不適用,但有時會咬你)
prependMy = mappend "my"
現在,這是你的表達方式。
getName s css = map intToChar . intToBase 26 <$> getIndex s css
為了清楚起見,現在有一些括號
getName s css = (map intToChar . intToBase 26) <$> (getIndex s css)
現在css不再是頂級了。以前不是,但現在更清楚了,不是。如果您可以重新排列運算式,s并且css實際上處于頂級呼叫中,那么您仍然可以取消。css在這種情況下,你可以通過做這樣的事情來擺脫。
getName s css = (map intToChar . intToBase 26) <$> (getIndex s css)
getName s css = ((map intToChar . intToBase 26) <$>) (getIndex s css)
getName s css = (((map intToChar . intToBase 26) <$>) . getIndex s) css
getName s = ((map intToChar . intToBase 26) <$>) . getIndex s
s然后您可以按照相同的邏輯擺脫
getName s = ((map intToChar . intToBase 26) <$>) . (getIndex s)
getName s = (((map intToChar . intToBase 26) <$>) .) (getIndex s)
getName s = ((((map intToChar . intToBase 26) <$>) .) . getIndex) s
getName = (((map intToChar . intToBase 26) <$>) .) . getIndex
但這并不比原版更具可讀性。像這樣洗掉引數稱為pointfreeing函式。它基本上可以用于任何功能,但應該謹慎使用,因為您很容易得到一些難以理解的東西。
uj5u.com熱心網友回復:
首先讓我們 eta-reduce 一個論點。這需要將運算子轉換為一個部分
getName s css = map intToChar . intToBase 26 <$> getIndex s css
getName s = (map intToChar . intToBase 26 <$>) . getIndex s
又名
getName s = fmap (map intToChar . intToBase 26) . getIndex s
現在,可以將函式后組合視為另一個函子操作?,但需要明確提及:
getName s = fmap (fmap (map intToChar . intToBase 26)) (getIndex s)
這很尷尬。一些庫定義了這樣的運算子<<$>>,允許將其壓縮為
getName s = map intToChar . intToBase 26 <<$>> getIndex s
但這并不能很好地擴展——每個嵌套深度都需要一個不同的運算子。不過,我們當然可以自己定義它:
infixl 4 <<<$>>>
(<<<$>>>) :: (Functor f, Functor g, Functor h)
=> (a->b) -> f (g (h a)) -> f (g (h b))
(<<<$>>>) = fmap . fmap . fmap
getName = map intToChar . intToBase 26 <<<$>>> getIndex
或者,您可以合并,即將不同的函子組合成一個:
getName s = getCompose $ map intToChar . intToBase 26 <$> Compose (getIndex s)
...哪種尺度也包括另一個論點
getName = getCompose . getCompose $ map intToChar . intToBase 26 <$> Compose (Compose getIndex)
但這顯然比以前的任何形式都沒有勝利。同樣的事情也可以用ReaderTmonad transformer來表達,但這同樣難以理解。對于涉及部分應用的合成運算子的各種無點逃逸也是如此。
tl; dr這不值得,只需保持原來的論點即可。
?我一般不喜歡(c->)函子。Haskell 有足夠多的仿函式,但它對于普通的舊函式具有出色的特殊語法,所以為什么不直接使用它并清楚什么仿函式只是一個函陣列合。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/427241.html
上一篇:打破回圈
